题意:给你n个数字,让你从中选出一些数字出来乘到一起,问能的到完全平方数的方案数。
分析:注意到最大的素因子最多为1997(303个),完全平方数中的所有素因子个数为偶数个,我们可以以此建立一个异或方程组,每个质因子对应一个方程,求出自由元个数的二次幂减一就是答案。
#include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> #define INF 0x3f3f3f3f #define eps 1e-9 #define MOD 1000000007 using namespace std; int T,n,tot,f[2005],F[310][310]; bool prime[2005]; void Swap(int a[310],int b[310]) //交换 { for(int i = 1;i <= n;i++) a[i] = a[i] + b[i]; for(int i = 1;i <= n;i++) b[i] = a[i] - b[i]; for(int i = 1;i <= n;i++) a[i] = a[i] - b[i]; } long long ksm(long long a,long long b) { long long ans = 1ll; while(b) { if(b & 1) ans = ans * a % MOD; a = a * a % MOD; b >>= 1; } return ans; } int main() { memset(prime,1,sizeof(prime)); prime[2] = true; for(int i = 2;i <= 2000;i++) if(prime[i]) for(int j = 2*i;j <= 2000;j += i) prime[j] = false; for(int i = 2;i <= 2000;i++) if(prime[i]) f[i] = ++tot; scanf("%d",&T); for(int t = 1;t <= T;t++) { int zy = 0; memset(F,0,sizeof(F)); scanf("%d",&n); for(int i = 1;i <= n;i++) { long long x; scanf("%I64d",&x); for(int k = 2;k <= sqrt(x);k++) while(x % k == 0) { F[f[k]][i] = (F[f[k]][i] + 1) % 2; x /= k; } if(x != 1) F[f[x]][i] = 1; } int now = 0; for(int i = 1;i <= n;i++) { int k = ++now; while(F[k][i] == 0 && k < tot) k++; if(F[k][i] == 0) { zy++; now--; continue; } if(k != now) Swap(F[now],F[k]); for(int j = now+1;j <= tot;j++) if(F[j][i] != 0) { for(int k = 1;k <= n;k++) F[j][k] ^= F[now][k]; } } printf("Case #%d:\n%I64d\n",t,(ksm(2,zy)-1LL+MOD)%MOD); } }