传送门
Cracking’ RSA
Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others)
Submit Statistic Next Problem
Problem Description
The following problem is somehow related to the final stage of many famous integer factorization algorithms involved in some cryptoanalytical problems, for example cracking well-known RSA public key system.
The most powerful of such algorithms, so called quadratic sieve descendant algorithms utilize the fact that if n = pq where p and q are large unknown primes needed to be found out, then if v2 = w2 (mod n) and u != v (mod n) and u != -v (mod n) then gcd(v + w, n) is a factor of n (either p or q).
Not getting further in the details of these algorithms, let us consider our problem. Given m integer numbers b1, b2, ... , bm such that all their prime factors are from the set of first t primes, the task is to find such a set S that S is a subset of {1, 2, ... ,m} and b1*b2*...*b|S|(bi belongs to S, i=1,2..|S|) is a perfect square i.e. equal to u2 for some integer u. Given such S we get one pair for testing (product of S elements stands for v when w is known from other steps of algorithms which are of no interest to us, testing performed is checking whether pair is nontrivial, i.e. u != v (mod n) and u != -v (mod n)). Since we want to factor n with maximum 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 is 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 bi such that all their prime factors are from t first primes (for example, if t = 3 all their prime factors are from the set {2, 3, 5}). 1 <= bi <= 109 for all i.
Output
Output the number of non-empty subsets of the given set bi, the product of numbers from which is a perfect square.
Sample Input
3 4
9 20 500 3
Sample Output
3
Source
Andrew Stankevich Contest 1
题目大意:
给定 t 和 n 分别表示有 t 个素因子(从2开始依次连续的)和 n 个数,然后让你求的是这 n 个数可以自由组合,求得所得的集合全是完全平方数的方法数。
解题思路:
PS:这是我第一次做高斯消元的题目
这个题目我们可以这么想 首先 我们将这 n 个素数进行素因子分解,n 个数肯定能由 t 个素数表示,那么我们可以将素数的指数是偶数的变为0,是奇数的变为1;打个比方:9就可以看作3^0,20就可以看作2^0 * 5^1,然后我们设一个x[]数组,那么x[i]的含义就是 是否选择第 i 个数字(如果选择就为 1,否则就为 0 )那么我们可以根据样例来解释一下:
3 4
9 20 500 3
因为只有3个素因子 那么 肯定就是 2 3 5
素因子 9 20 500 3
2: 0 0 0 0
3: 0 0 0 1
5: 0 1 1 0
0&x1 ^ 0&x2 ^ 0&x3 ^ 0&x4 = 0
0&x1 ^ 0&x2 ^ 0&x3 ^ 1&x4 = 0
0&x1 ^ 1&x2 ^ 1&x3 ^ 0&x4 = 0
那么我们得到了这么一个方程组,所以我们 只需要求一下这个方程组的自由变元的个数,然后我们要求的就是2^(自由变元的个数)-1(空集去掉)
现在来解释 一下这个方程组的意思,因为x[i]表示的是取与不取这个数 而我们最终要求的是完全平方数 所以最后所有的指数肯定是 偶数,那么异或之后肯定就是 0 了,所以就列出了上面这个方程,那么我们在根据 (a&b) ^ (a&c) = a ^ (b&c)这个公式就可以化简了 然后借助高斯消元搞一搞就行了,最后别忘了大数 算一发(我直接套的模板)
My 代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
using namespace std;
#define DIGIT 4 //四位隔开,即万进制
#define DEPTH 10000 //万进制
#define MAXX 2000+5 //题目最大位数/4,要不大直接设为最大位数也行
typedef int bignum_t[MAXX+1];
/************************************************************************/
/* 读取操作数,对操作数进行处理存储在数组里 */
/************************************************************************/
int read(bignum_t a,istream&is=cin)
{
char buf[MAXX*DIGIT+1],ch ;
int i,j ;
memset((void*)a,0,sizeof(bignum_t));
if(!(is>>buf))return 0 ;
for(a[0]=strlen(buf),i=a[0]/2-1;i>=0;i--)
ch=buf[i],buf[i]=buf[a[0]-1-i],buf[a[0]-1-i]=ch ;
for(a[0]=(a[0]+DIGIT-1)/DIGIT,j=strlen(buf);j<a[0]*DIGIT;buf[j++]='0');
for(i=1;i<=a[0];i++)
for(a[i]=0,j=0;j<DIGIT;j++)
a[i]=a[i]*10+buf[i*DIGIT-1-j]-'0' ;
for(;!a[a[0]]&&a[0]>1;a[0]--);
return 1 ;
}
void write(const bignum_t a,ostream&os=cout)
{
int i,j ;
for(os<<a[i=a[0]],i--;i;i--)
for(j=DEPTH/10;j;j/=10)
os<<a[i]/j%10 ;
}
int comp(const bignum_t a,const bignum_t b)
{
int i ;
if(a[0]!=b[0])
return a[0]-b[0];
for(i=a[0];i;i--)
if(a[i]!=b[i])
return a[i]-b[i];
return 0 ;
}
int comp(const bignum_t a,const int b)
{
int c[12]=
{
1
}
;
for(c[1]=b;c[c[0]]>=DEPTH;c[c[0]+1]=c[c[0]]/DEPTH,c[c[0]]%=DEPTH,c[0]++);
return comp(a,c);
}
int comp(const bignum_t a,const int c,const int d,const bignum_t b)
{
int i,t=0,O=-DEPTH*2 ;
if(b[0]-a[0]<d&&c)
return 1 ;
for(i=b[0];i>d;i--)
{
t=t*DEPTH+a[i-d]*c-b[i];
if(t>0)return 1 ;
if(t<O)return 0 ;
}
for(i=d;i;i--)
{
t=t*DEPTH-b[i];
if(t>0)return 1 ;
if(t<O)return 0 ;
}
return t>0 ;
}
/************************************************************************/
/* 大数与大数相加 */
/************************************************************************/
void add(bignum_t a,const bignum_t b)
{
int i ;
for(i=1;i<=b[0];i++)
if((a[i]+=b[i])>=DEPTH)
a[i]-=DEPTH,a[i+1]++;
if(b[0]>=a[0])
a[0]=b[0];
else
for(;a[i]>=DEPTH&&i<a[0];a[i]-=DEPTH,i++,a[i]++);
a[0]+=(a[a[0]+1]>0);
}
/************************************************************************/
/* 大数与小数相加 */
/************************************************************************/
void add(bignum_t a,const int b)
{
int i=1 ;
for(a[1]+=b;a[i]>=DEPTH&&i<a[0];a[i+1]+=a[i]/DEPTH,a[i]%=DEPTH,i++);
for(;a[a[0]]>=DEPTH;a[a[0]+1]=a[a[0]]/DEPTH,a[a[0]]%=DEPTH,a[0]++);
}
/************************************************************************/
/* 大数相减(被减数>=减数) */
/************************************************************************/
void sub(bignum_t a,const bignum_t b)
{
int i ;
for(i=1;i<=b[0];i++)
if((a[i]-=b[i])<0)
a[i+1]--,a[i]+=DEPTH ;
for(;a[i]<0;a[i]+=DEPTH,i++,a[i]--);
for(;!a[a[0]]&&a[0]>1;a[0]--);
}
/************************************************************************/
/* 大数减去小数(被减数>=减数) */
/************************************************************************/
void sub(bignum_t a,const int b)
{
int i=1 ;
for(a[1]-=b;a[i]<0;a[i+1]+=(a[i]-DEPTH+1)/DEPTH,a[i]-=(a[i]-DEPTH+1)/DEPTH*DEPTH,i++);
for(;!a[a[0]]&&a[0]>1;a[0]--);
}
void sub(bignum_t a,const bignum_t b,const int c,const int d)
{
int i,O=b[0]+d ;
for(i=1+d;i<=O;i++)
if((a[i]-=b[i-d]*c)<0)
a[i+1]+=(a[i]-DEPTH+1)/DEPTH,a[i]-=(a[i]-DEPTH+1)/DEPTH*DEPTH ;
for(;a[i]<0;a[i+1]+=(a[i]-DEPTH+1)/DEPTH,a[i]-=(a[i]-DEPTH+1)/DEPTH*DEPTH,i++);
for(;!a[a[0]]&&a[0]>1;a[0]--);
}
/************************************************************************/
/* 大数相乘,读入被乘数a,乘数b,结果保存在c[] */
/************************************************************************/
void mul(bignum_t c,const bignum_t a,const bignum_t b)
{
int i,j ;
memset((void*)c,0,sizeof(bignum_t));
for(c[0]=a[0]+b[0]-1,i=1;i<=a[0];i++)
for(j=1;j<=b[0];j++)
if((c[i+j-1]+=a[i]*b[j])>=DEPTH)
c[i+j]+=c[i+j-1]/DEPTH,c[i+j-1]%=DEPTH ;
for(c[0]+=(c[c[0]+1]>0);!c[c[0]]&&c[0]>1;c[0]--);
}
/************************************************************************/
/* 大数乘以小数,读入被乘数a,乘数b,结果保存在被乘数 */
/************************************************************************/
void mul(bignum_t a,const int b)
{
int i ;
for(a[1]*=b,i=2;i<=a[0];i++)
{
a[i]*=b ;
if(a[i-1]>=DEPTH)
a[i]+=a[i-1]/DEPTH,a[i-1]%=DEPTH ;
}
for(;a[a[0]]>=DEPTH;a[a[0]+1]=a[a[0]]/DEPTH,a[a[0]]%=DEPTH,a[0]++);
for(;!a[a[0]]&&a[0]>1;a[0]--);
}
void mul(bignum_t b,const bignum_t a,const int c,const int d)
{
int i ;
memset((void*)b,0,sizeof(bignum_t));
for(b[0]=a[0]+d,i=d+1;i<=b[0];i++)
if((b[i]+=a[i-d]*c)>=DEPTH)
b[i+1]+=b[i]/DEPTH,b[i]%=DEPTH ;
for(;b[b[0]+1];b[0]++,b[b[0]+1]=b[b[0]]/DEPTH,b[b[0]]%=DEPTH);
for(;!b[b[0]]&&b[0]>1;b[0]--);
}
/**************************************************************************/
/* 大数相除,读入被除数a,除数b,结果保存在c[]数组 */
/* 需要comp()函数 */
/**************************************************************************/
void div(bignum_t c,bignum_t a,const bignum_t b)
{
int h,l,m,i ;
memset((void*)c,0,sizeof(bignum_t));
c[0]=(b[0]<a[0]+1)?(a[0]-b[0]+2):1 ;
for(i=c[0];i;sub(a,b,c[i]=m,i-1),i--)
for(h=DEPTH-1,l=0,m=(h+l+1)>>1;h>l;m=(h+l+1)>>1)
if(comp(b,m,i-1,a))h=m-1 ;
else l=m ;
for(;!c[c[0]]&&c[0]>1;c[0]--);
c[0]=c[0]>1?c[0]:1 ;
}
void div(bignum_t a,const int b,int&c)
{
int i ;
for(c=0,i=a[0];i;c=c*DEPTH+a[i],a[i]=c/b,c%=b,i--);
for(;!a[a[0]]&&a[0]>1;a[0]--);
}
/************************************************************************/
/* 大数平方根,读入大数a,结果保存在b[]数组里 */
/* 需要comp()函数 */
/************************************************************************/
void sqrt(bignum_t b,bignum_t a)
{
int h,l,m,i ;
memset((void*)b,0,sizeof(bignum_t));
for(i=b[0]=(a[0]+1)>>1;i;sub(a,b,m,i-1),b[i]+=m,i--)
for(h=DEPTH-1,l=0,b[i]=m=(h+l+1)>>1;h>l;b[i]=m=(h+l+1)>>1)
if(comp(b,m,i-1,a))h=m-1 ;
else l=m ;
for(;!b[b[0]]&&b[0]>1;b[0]--);
for(i=1;i<=b[0];b[i++]>>=1);
}
/************************************************************************/
/* 返回大数的长度 */
/************************************************************************/
int length(const bignum_t a)
{
int t,ret ;
for(ret=(a[0]-1)*DIGIT,t=a[a[0]];t;t/=10,ret++);
return ret>0?ret:1 ;
}
/************************************************************************/
/* 返回指定位置的数字,从低位开始数到第b位,返回b位上的数 */
/************************************************************************/
int digit(const bignum_t a,const int b)
{
int i,ret ;
for(ret=a[(b-1)/DIGIT+1],i=(b-1)%DIGIT;i;ret/=10,i--);
return ret%10 ;
}
/************************************************************************/
/* 返回大数末尾0的个数 */
/************************************************************************/
int zeronum(const bignum_t a)
{
int ret,t ;
for(ret=0;!a[ret+1];ret++);
for(t=a[ret+1],ret*=DIGIT;!(t%10);t/=10,ret++);
return ret ;
}
void comp(int*a,const int l,const int h,const int d)
{
int i,j,t ;
for(i=l;i<=h;i++)
for(t=i,j=2;t>1;j++)
while(!(t%j))
a[j]+=d,t/=j ;
}
void convert(int*a,const int h,bignum_t b)
{
int i,j,t=1 ;
memset(b,0,sizeof(bignum_t));
for(b[0]=b[1]=1,i=2;i<=h;i++)
if(a[i])
for(j=a[i];j;t*=i,j--)
if(t*i>DEPTH)
mul(b,t),t=1 ;
mul(b,t);
}
/************************************************************************/
/* 组合数 */
/************************************************************************/
void combination(bignum_t a,int m,int n)
{
int*t=new int[m+1];
memset((void*)t,0,sizeof(int)*(m+1));
comp(t,n+1,m,1);
comp(t,2,m-n,-1);
convert(t,m,a);
delete[]t ;
}
/************************************************************************/
/* 排列数 */
/************************************************************************/
void permutation(bignum_t a,int m,int n)
{
int i,t=1 ;
memset(a,0,sizeof(bignum_t));
a[0]=a[1]=1 ;
for(i=m-n+1;i<=m;t*=i++)
if(t*i>DEPTH)
mul(a,t),t=1 ;
mul(a,t);
}
#define SGN(x) ((x)>0?1:((x)<0?-1:0))
#define ABS(x) ((x)>0?(x):-(x))
int read(bignum_t a,int&sgn,istream&is=cin)
{
char str[MAXX*DIGIT+2],ch,*buf ;
int i,j ;
memset((void*)a,0,sizeof(bignum_t));
if(!(is>>str))return 0 ;
buf=str,sgn=1 ;
if(*buf=='-')sgn=-1,buf++;
for(a[0]=strlen(buf),i=a[0]/2-1;i>=0;i--)
ch=buf[i],buf[i]=buf[a[0]-1-i],buf[a[0]-1-i]=ch ;
for(a[0]=(a[0]+DIGIT-1)/DIGIT,j=strlen(buf);j<a[0]*DIGIT;buf[j++]='0');
for(i=1;i<=a[0];i++)
for(a[i]=0,j=0;j<DIGIT;j++)
a[i]=a[i]*10+buf[i*DIGIT-1-j]-'0' ;
for(;!a[a[0]]&&a[0]>1;a[0]--);
if(a[0]==1&&!a[1])sgn=0 ;
return 1 ;
}
struct bignum
{
bignum_t num ;
int sgn ;
public :
inline bignum()
{
memset(num,0,sizeof(bignum_t));
num[0]=1 ;
sgn=0 ;
}
inline int operator!()
{
return num[0]==1&&!num[1];
}
inline bignum&operator=(const bignum&a)
{
memcpy(num,a.num,sizeof(bignum_t));
sgn=a.sgn ;
return*this ;
}
inline bignum&operator=(const int a)
{
memset(num,0,sizeof(bignum_t));
num[0]=1 ;
sgn=SGN (a);
add(num,sgn*a);
return*this ;
}
;
inline bignum&operator+=(const bignum&a)
{
if(sgn==a.sgn)add(num,a.num);
else if
(sgn&&a.sgn)
{
int ret=comp(num,a.num);
if(ret>0)sub(num,a.num);
else if(ret<0)
{
bignum_t t ;
memcpy(t,num,sizeof(bignum_t));
memcpy(num,a.num,sizeof(bignum_t));
sub (num,t);
sgn=a.sgn ;
}
else memset(num,0,sizeof(bignum_t)),num[0]=1,sgn=0 ;
}
else if(!sgn)
memcpy(num,a.num,sizeof(bignum_t)),sgn=a.sgn ;
return*this ;
}
inline bignum&operator+=(const int a)
{
if(sgn*a>0)add(num,ABS(a));
else if(sgn&&a)
{
int ret=comp(num,ABS(a));
if(ret>0)sub(num,ABS(a));
else if(ret<0)
{
bignum_t t ;
memcpy(t,num,sizeof(bignum_t));
memset(num,0,sizeof(bignum_t));
num[0]=1 ;
add(num,ABS (a));
sgn=-sgn ;
sub(num,t);
}
else memset(num,0,sizeof(bignum_t)),num[0]=1,sgn=0 ;
}
else if
(!sgn)sgn=SGN(a),add(num,ABS(a));
return*this ;
}
inline bignum operator+(const bignum&a)
{
bignum ret ;
memcpy(ret.num,num,sizeof (bignum_t));
ret.sgn=sgn ;
ret+=a ;
return ret ;
}
inline bignum operator+(const int a)
{
bignum ret ;
memcpy(ret.num,num,sizeof (bignum_t));
ret.sgn=sgn ;
ret+=a ;
return ret ;
}
inline bignum&operator-=(const bignum&a)
{
if(sgn*a.sgn<0)add(num,a.num);
else if
(sgn&&a.sgn)
{
int ret=comp(num,a.num);
if(ret>0)sub(num,a.num);
else if(ret<0)
{
bignum_t t ;
memcpy(t,num,sizeof(bignum_t));
memcpy(num,a.num,sizeof(bignum_t));
sub(num,t);
sgn=-sgn ;
}
else memset(num,0,sizeof(bignum_t)),num[0]=1,sgn=0 ;
}
else if(!sgn)add (num,a.num),sgn=-a.sgn ;
return*this ;
}
inline bignum&operator-=(const int a)
{
if(sgn*a<0)add(num,ABS(a));
else if(sgn&&a)
{
int ret=comp(num,ABS(a));
if(ret>0)sub(num,ABS(a));
else if(ret<0)
{
bignum_t t ;
memcpy(t,num,sizeof(bignum_t));
memset(num,0,sizeof(bignum_t));
num[0]=1 ;
add(num,ABS(a));
sub(num,t);
sgn=-sgn ;
}
else memset(num,0,sizeof(bignum_t)),num[0]=1,sgn=0 ;
}
else if
(!sgn)sgn=-SGN(a),add(num,ABS(a));
return*this ;
}
inline bignum operator-(const bignum&a)
{
bignum ret ;
memcpy(ret.num,num,sizeof(bignum_t));
ret.sgn=sgn ;
ret-=a ;
return ret ;
}
inline bignum operator-(const int a)
{
bignum ret ;
memcpy(ret.num,num,sizeof(bignum_t));
ret.sgn=sgn ;
ret-=a ;
return ret ;
}
inline bignum&operator*=(const bignum&a)
{
bignum_t t ;
mul(t,num,a.num);
memcpy(num,t,sizeof(bignum_t));
sgn*=a.sgn ;
return*this ;
}
inline bignum&operator*=(const int a)
{
mul(num,ABS(a));
sgn*=SGN(a);
return*this ;
}
inline bignum operator*(const bignum&a)
{
bignum ret ;
mul(ret.num,num,a.num);
ret.sgn=sgn*a.sgn ;
return ret ;
}
inline bignum operator*(const int a)
{
bignum ret ;
memcpy(ret.num,num,sizeof (bignum_t));
mul(ret.num,ABS(a));
ret.sgn=sgn*SGN(a);
return ret ;
}
inline bignum&operator/=(const bignum&a)
{
bignum_t t ;
div(t,num,a.num);
memcpy (num,t,sizeof(bignum_t));
sgn=(num[0]==1&&!num[1])?0:sgn*a.sgn ;
return*this ;
}
inline bignum&operator/=(const int a)
{
int t ;
div(num,ABS(a),t);
sgn=(num[0]==1&&!num [1])?0:sgn*SGN(a);
return*this ;
}
inline bignum operator/(const bignum&a)
{
bignum ret ;
bignum_t t ;
memcpy(t,num,sizeof(bignum_t));
div(ret.num,t,a.num);
ret.sgn=(ret.num[0]==1&&!ret.num[1])?0:sgn*a.sgn ;
return ret ;
}
inline bignum operator/(const int a)
{
bignum ret ;
int t ;
memcpy(ret.num,num,sizeof(bignum_t));
div(ret.num,ABS(a),t);
ret.sgn=(ret.num[0]==1&&!ret.num[1])?0:sgn*SGN(a);
return ret ;
}
inline bignum&operator%=(const bignum&a)
{
bignum_t t ;
div(t,num,a.num);
if(num[0]==1&&!num[1])sgn=0 ;
return*this ;
}
inline int operator%=(const int a)
{
int t ;
div(num,ABS(a),t);
memset(num,0,sizeof (bignum_t));
num[0]=1 ;
add(num,t);
return t ;
}
inline bignum operator%(const bignum&a)
{
bignum ret ;
bignum_t t ;
memcpy(ret.num,num,sizeof(bignum_t));
div(t,ret.num,a.num);
ret.sgn=(ret.num[0]==1&&!ret.num [1])?0:sgn ;
return ret ;
}
inline int operator%(const int a)
{
bignum ret ;
int t ;
memcpy(ret.num,num,sizeof(bignum_t));
div(ret.num,ABS(a),t);
memset(ret.num,0,sizeof(bignum_t));
ret.num[0]=1 ;
add(ret.num,t);
return t ;
}
inline bignum&operator++()
{
*this+=1 ;
return*this ;
}
inline bignum&operator--()
{
*this-=1 ;
return*this ;
}
;
inline int operator>(const bignum&a)
{
return sgn>0?(a.sgn>0?comp(num,a.num)>0:1):(sgn<0?(a.sgn<0?comp(num,a.num)<0:0):a.sgn<0);
}
inline int operator>(const int a)
{
return sgn>0?(a>0?comp(num,a)>0:1):(sgn<0?(a<0?comp(num,-a)<0:0):a<0);
}
inline int operator>=(const bignum&a)
{
return sgn>0?(a.sgn>0?comp(num,a.num)>=0:1):(sgn<0?(a.sgn<0?comp(num,a.num)<=0:0):a.sgn<=0);
}
inline int operator>=(const int a)
{
return sgn>0?(a>0?comp(num,a)>=0:1):(sgn<0?(a<0?comp(num,-a)<=0:0):a<=0);
}
inline int operator<(const bignum&a)
{
return sgn<0?(a.sgn<0?comp(num,a.num)>0:1):(sgn>0?(a.sgn>0?comp(num,a.num)<0:0):a.sgn>0);
}
inline int operator<(const int a)
{
return sgn<0?(a<0?comp(num,-a)>0:1):(sgn>0?(a>0?comp(num,a)<0:0):a>0);
}
inline int operator<=(const bignum&a)
{
return sgn<0?(a.sgn<0?comp(num,a.num)>=0:1):(sgn>0?(a.sgn>0?comp(num,a.num)<=0:0):a.sgn>=0);
}
inline int operator<=(const int a)
{
return sgn<0?(a<0?comp(num,-a)>=0:1):
(sgn>0?(a>0?comp(num,a)<=0:0):a>=0);
}
inline int operator==(const bignum&a)
{
return(sgn==a.sgn)?!comp(num,a.num):0 ;
}
inline int operator==(const int a)
{
return(sgn*a>=0)?!comp(num,ABS(a)):0 ;
}
inline int operator!=(const bignum&a)
{
return(sgn==a.sgn)?comp(num,a.num):1 ;
}
inline int operator!=(const int a)
{
return(sgn*a>=0)?comp(num,ABS(a)):1 ;
}
inline int operator[](const int a)
{
return digit(num,a);
}
friend inline istream&operator>>(istream&is,bignum&a)
{
read(a.num,a.sgn,is);
return is ;
}
friend inline ostream&operator<<(ostream&os,const bignum&a)
{
if(a.sgn<0)
os<<'-' ;
write(a.num,os);
return os ;
}
friend inline bignum sqrt(const bignum&a)
{
bignum ret ;
bignum_t t ;
memcpy(t,a.num,sizeof(bignum_t));
sqrt(ret.num,t);
ret.sgn=ret.num[0]!=1||ret.num[1];
return ret ;
}
friend inline bignum sqrt(const bignum&a,bignum&b)
{
bignum ret ;
memcpy(b.num,a.num,sizeof(bignum_t));
sqrt(ret.num,b.num);
ret.sgn=ret.num[0]!=1||ret.num[1];
b.sgn=b.num[0]!=1||ret.num[1];
return ret ;
}
inline int length()
{
return :: length(num);
}
inline int zeronum()
{
return :: zeronum(num);
}
inline bignum C(const int m,const int n)
{
combination(num,m,n);
sgn=1 ;
return*this ;
}
inline bignum P(const int m,const int n)
{
permutation(num,m,n);
sgn=1 ;
return*this ;
}
};
/**+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
typedef long long LL;
const int MAXN = 1e2+5;
int equ, var;///equ个方程 var个变量
int a[MAXN][MAXN];///增广矩阵
int x[MAXN];///解的数目
bool free_x[MAXN];///判断是不是自由变元
int free_num;///自由变元的个数
inline int GCD(int m, int n)
{
if(n == 0)
return m;
return GCD(n, m%n);
}
inline int LCM(int a, int b)
{
return a/GCD(a,b)*b;
}
int Gauss()
{
int Max_r;///当前列绝对值最大的存在的行
///col:处理当前的列
int row=0;
for(int col=0; row<equ&&col<var; row++,col++)
{
Max_r = row;
for(int i=row+1; i<equ; i++)
if(abs(a[i][col]) > abs(a[Max_r][col]))
Max_r = i;
if(Max_r != row)
for(int i=0; i<var+1; i++)
swap(a[row][i], a[Max_r][i]);
if(a[row][col] == 0)
{
row--;
continue;
}
for(int i=row+1; i<equ; i++)
{
if(a[i][col])
{
for(int j=col; j<var; j++)
{
a[i][j] ^= a[row][j];
}
}
}
}
return row;
}
int b[MAXN];
const int MAX = 1e6+5;
int p[MAX];
bool prime[MAX];
int k;
void isprime()
{
k = 0;
memset(prime, false, sizeof(prime));
for(LL i=2; i<MAX; i++)
{
if(!prime[i])
{
p[k++] = i;
for(LL j=i*i; j<MAX; j+=i)
prime[j] = true;
}
}
}
int main()
{
isprime();
while(cin>>equ>>var)
{
memset(a, 0, sizeof(a));
for(int i=0; i<var; i++)
{
int x, sum;
cin>>x;
for(int j=0; j<equ; j++)
{
sum = 0;
if(x%p[j] == 0)
{
int mm = x;
while(mm%p[j]==0)
{
sum++;
mm /= p[j];
}
}
///构造系数矩阵
if(sum & 1)
a[j][i] = 1;
else
a[j][i] = 0;
}
}
int ans = var - Gauss();
bignum m;
m = 1;
for(int i=0; i<ans; i++)
{
m = m*2;
}
cout<<m-1<<endl;
}
return 0;
}