题意:给n个数,从n个数中抽取x(x>=1)个数,这x个数相乘为完全平方数,求一共有多少种取法,结果模1000000007。
思路:每个数可以拆成素数相乘的形式,例如:
x1 2=2^1 * 3^0 * 5^0;
x2 3=2^0 * 3^1 * 5^0;
x3 4=2^2 * 3^0 * 5^0;
x4 5=2^0 * 3^0 * 5^1;
x5 6=2^1 * 3^1 * 5^0;
x6 15=2^0 * 3^1 * 5^1;
用xi表示第i个数选或不选,xi的取值为0或1;因为相乘结果为完全平方数,所以最后的完全平方数表示成素数相乘的形式后,每个素数的幂一定是偶数,即模2等于0:
2 (x1+2*x3+x5)%2=0
3 (x2+x5+x6)%2=0
5 (x4+x6)%2=0
将上面的式子转化为异或方程组,求解有m个自由变量,每个自由变量都可以取0或1,最终答案为2^m-1(去掉全0的情况);
#include <bits/stdc++.h>
using namespace std;
#define MAXN 2000
int prime[MAXN+5];
int a[MAXN+5][305];
int free_num;
int free_x[MAXN];
int x[310];
int equ,var;
const int mod=1000000007;
void getprime()
{
int i,j;
memset(prime,1,sizeof(prime));
prime[0]=prime[1]=0;
for(i=2;i<=MAXN;i++)
{
if(prime[i])
prime[++prime[0]]=i;
for(j=1;j<=prime[0]&&i*prime[j]<=MAXN;j++)
{
prime[i*prime[j]]=0;
if(i%prime[j]==0)
break;
}
}
}
void geta(int id,long long num)
{
int i;
i=1;
while(num!=1)
{
while(num%prime[i]==0)
{
num/=prime[i];
a[i-1][id]^=1;
}
i++;
}
}
//返回值为-1表示无解,为0是唯一解,否则返回自由变元个数
int Gauss()
{
int max_r, col, k;
free_num = 0;
for(k = 0, col = 0; k < equ && col < var; k++, col++)
{
max_r = k;
for(int i = k ; i < equ; i++)
if(abs(a[i][col]==1)
{
max_r = i;
break;
}
if(a[max_r][col] == 0)
{
k--;
free_x[free_num++] = col; //自由变元
continue;
}
if(max_r != k)
{
for(int j = col; j < var+1; j++)
swap(a[k][j],a[max_r][j]);
}
for(int i = k+1; i < equ;i++)
if(a[i][col] != 0)
for(int j = col; j < var+1;j++)
a[i][j] ^= a[k][j];
}
for(int i = k;i < equ;i++)
if(a[i][col] != 0)
return -1;
if(k < var)return var-k;
return 0;
}
int main()
{
int ans;
int t;
int n;
int i;
int cas;
int freex;
long long num;
scanf("%d",&t);
getprime();
//printf("%d
",prime[0]);
for(cas=1;cas<=t;cas++)
{
memset(a,0,sizeof(a));
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%I64d",&num);
geta(i,num);
}
equ=prime[0];
var=n;
freex=Gauss();
//printf("::%d
",freex);
if(freex==-1)
ans=0;
else if(freex==0)
ans=0;
else
{
ans=1;
for(i=0;i<freex;i++)
{
ans=(2*ans)%mod;
}
ans--;
}
printf("Case #%d:
%d
",cas,ans);
}
return 0;
}