从数组中选择几个数,要求他们的乘积可以开平方,问有多少种方案。
先将单个数拆分成质因子,对于这个数而言,那些指数为奇数的质因子会使这个数无法被开平方。
所以我们需要选择一个对应质因子指数为奇数的元素,将他们两个放在一个方案中,但是又有可能会引入其他的质因子。
这样就变成了求解行列式中*变元的数量问题。
将数组转换成行列式,利用高斯消元求解。
代码如下:
#include<cstdio> #include<cstring> #include<vector> #include<algorithm> using namespace std; bool pri[505]; int a[501][501]; int max_; int t, n; long long x; vector<int>V; void Prime(){ memset(pri,1,sizeof(pri)); pri[0] = pri[1] = 0; for(int i=2;i<501;i++)if(pri[i]){ V.push_back(i);//对素数离散一下 优化一下 for(int j=i<<1;j<501;j+=i) pri[i] = 0; } } void init(){ memset(a,0,sizeof(a)); max_ = 0; } int gauss(){// 高斯消元 int i = 0, j = 0; while(i<=max_ && j<n){ int k = i; for(;k<=max_;k++) if(a[k][j])break; if(k != max_ + 1){ for(int l=0;l<n;l++){ // 第j个等式的 k位上为 1 // 将第 k 行与第 i 行 进行 行交换 swap(a[i][l],a[k][l]); } for(int k=i+1;k<=max_;k++){ if(a[k][j]){ for(int l=j;l<n;l++) a[k][l] ^= a[i][l];// 这里是优化后的式子 } } i++; } j++; } return n-i; } int main(){ Prime(); scanf("%d",&t); while(t--){ init(); scanf("%d",&n); for(int i=0;i<n;i++){ scanf("%lld",&x); for(int j=0;j<V.size() && V[j]<= x;j++){ while(x%V[j] == 0){ a[j][i] ^= 1; // 若 质因子的指数为偶数 则行列式对应位上为 0 // 奇数 为 1 max_ = max(max_, j); // 记录一下最大值, 优化 x /= V[j]; } } } printf("%lld\n",(1ll<<gauss())-1); } return 0; }View Code