SGU 200.Cracking RSA(ガウスの消元は自由元の個数を求める)

25981 ワード

テーマリンク:http://acm.sgu.ru/problem.php?contest=0&problem=200
200.Cracking RSA
time limit per test:0.25 sec.
memory limit per test:65536 KB
input:standard
out put:standard
The follwing problem is somehow related to the final stage of many famous integer factoriation algorithms involved in some cryptanlytical probles,for example cracking well-known RSA public system. 
The most powerful of such algorithms、so caled quadratic sieve descendant algorithms、utilize the fact that if n=p q where p and q are unknown predtobe found、then if v
2=w
2 (mod n)、u≠v(mod n)and u≠v(mod n)、then gcd(v+w,n)is a factor of n(ether p or q) 
Not getting Frther in the details of these algorithms,let us consider our proble m.Gven m integer numbers b
1,b
2,…,b
m such that all their preme factors are from the set of first prmes,the task is to find such a subset S of{1,2,…,m}that product of b
i for i from S is a perfect square i.e.equal to u
2 for some integer u.Given such S we get one pair for testing(product of S elemens stands stands forevwhen w w w w w w w w w isknowwn ffrom otheeps of algorithms which arar of no interest to us、testing perperformed ischchchchchewheheheheckinininininininininininininininininininininininininininininininininininininininininininininininininininininininininininininininininininininininininininininininininininininm possible probability、we would like to get as many such sets as possible.So the interesting problem could be to calculate the number of all such sets.This exactly your task. 
Input
The first line of the input file contains two integers t and m(1≦t≦100,1≦m≦100).The second line of the input file contains m integer numbers b
i such that all their prive factors are from t first premens(for example、if t=3 all their prive factors are from the set{2,3,5}.1≦b
i ≦10
9 for all i. 
Output
Output the number of non-empty subsets of the given set{b
i}the product of numbers from which is a perfect square 
Sample test(s)
Input
 
 
3 4 9 20,500 3 
 
 
Output
 
 

 
 
 
 
 
この問題はm個の数を与えています。このm個の数の質因子は全部前のt個の素数からなります。
このm個の数のサブセットがいくつかありますか?それらの積は完全な平方数になります。
 
 
完全な平方数とは、各素数の指数が偶数であることを要求する。
各質量因子に対して方程式を構築した。モード2の線形方程式群となる。
この方程式グループを解くには何個の自由変数がありますか?答えは2^ret-1で、空セットを取り除く場合です。
 
 
  1 /* ***********************************************
  2 Author        :kuangbin
  3 Created Time  :2014-1-20 9:19:03
  4 File Name     :E:\2014ACM\SGU\SGU200.cpp
  5 ************************************************ */
  6 
  7 #include <stdio.h>
  8 #include <string.h>
  9 #include <iostream>
 10 #include <algorithm>
 11 #include <vector>
 12 #include <queue>
 13 #include <set>
 14 #include <map>
 15 #include <string>
 16 #include <math.h>
 17 using namespace std;
 18 
 19 //     
 20 void add(char a[],char b[],char c[])
 21 {
 22     int len1 = strlen(a);
 23     int len2 = strlen(b);
 24     int len = max(len1,len2);
 25     int up = 0;
 26     for(int i = 0;i < len;i++)
 27     {
 28         int tmp = 0;
 29         if(i < len1) tmp += a[i] - '0';
 30         if(i < len2) tmp += b[i] - '0';
 31         tmp += up;
 32         c[i] = tmp%10 + '0';
 33         up = tmp/10;
 34     }
 35     if(up)
 36         c[len++] = up + '0';
 37     c[len] = 0;
 38 }
 39 void SUB_ONE(char a[])
 40 {
 41     int id = 0;
 42     while(a[id] == '0')id++;
 43     a[id]--;
 44     for(int i = 0;i < id;i++)
 45         a[i] = '9';
 46     int len = strlen(a);
 47     while(len > 1 && a[len-1] == '0')len--;
 48     a[len] = 0;
 49 }
 50 
 51 int equ,var;
 52 int a[110][110];
 53 int x[110];
 54 int free_x[110];
 55 int free_num;
 56 
 57 //    -1    , 0    ,          
 58 int Gauss()
 59 {
 60     int max_r, col, k;
 61     free_num = 0;
 62     for(k = 0, col = 0; k < equ && col < var; k++, col++)
 63     {
 64         max_r = k;
 65         for(int i = k+1 ; i < equ; i++)
 66             if(abs(a[i][col]) > abs(a[max_r][col]))
 67                 max_r = i;
 68         if(a[max_r][col] == 0)
 69         {
 70             k--;
 71             free_x[free_num++] = col; //    
 72             continue;
 73         }
 74         if(max_r != k)
 75         {
 76             for(int j = col; j < var+1; j++)
 77                 swap(a[k][j],a[max_r][j]);
 78         }
 79         for(int i = k+1; i < equ;i++)
 80             if(a[i][col] != 0)
 81                 for(int j = col; j < var+1;j++)
 82                     a[i][j] ^= a[k][j];
 83     }
 84     for(int i = k;i < equ;i++)
 85         if(a[i][col] != 0)
 86             return -1;
 87     if(k < var)return var-k;
 88     for(int i = var-1; i >= 0;i--)
 89     {
 90         x[i] = a[i][var];
 91         for(int j = i+1; j < var;j++)
 92             x[i] ^= (a[i][j] && x[j]);
 93     }
 94     return 0;
 95 }
 96 
 97 const int MAXN = 1000;
 98 int prime[MAXN+1];
 99 void getPrime()
100 {
101     memset(prime,0,sizeof(prime));
102     for(int i = 2;i <= MAXN;i++)
103     {
104         if(!prime[i])prime[++prime[0]] = i;
105         for(int j = 1;j <= prime[0] && prime[j] <= MAXN/i;j++)
106         {
107             prime[prime[j]*i] = 1;
108             if(i%prime[j] == 0)break;
109         }
110     }
111 }
112 
113 int b[110];
114 char str1[110],str2[110];
115 
116 int main()
117 {
118     //freopen("in.txt","r",stdin);
119     //freopen("out.txt","w",stdout);
120     getPrime();
121     int t,m;
122     while(scanf("%d%d",&t,&m) != EOF)
123     {
124         for(int i = 0;i < m;i++)
125             scanf("%d",&b[i]);
126         equ = t;
127         var = m;
128         for(int i = 0;i < t;i++)
129             for(int j = 0;j < m;j++)
130             {
131                 int cnt = 0;
132                 while(b[j]%prime[i+1] == 0)
133                 {
134                     cnt++;
135                     b[j] /= prime[i+1];
136                 }
137                 a[i][j] = (cnt&1);
138             }
139         for(int i = 0;i < t;i++)
140             a[i][m] = 0;
141         int ret = Gauss();
142         strcpy(str1,"1");
143         for(int i = 0;i < ret;i++)
144         {
145             add(str1,str1,str2);
146             strcpy(str1,str2);
147         }
148         SUB_ONE(str1);
149         int len = strlen(str1);
150         for(int i = len-1;i >= 0;i--)
151             printf("%c",str1[i]);
152         printf("
"); 153 } 154 return 0; 155 }