#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 500 + 10;
const int maxp = 100;
int vis[maxn];
int prime[maxp];
int gen_primes(int n) {
int m = (int)sqrt(n+0.5);
memset(vis, 0, sizeof(vis));
for(int i = 2; i <= m; i++) if(!vis[i])
for(int j = i*i; j <= n; j+=i) vis[j] = 1;
int c = 0;
for(int i = 2; i <= n; i++) if(!vis[i])
prime[c++] = i;
return c;
}
typedef int Matrix[maxn][maxn];
// m个方程,n个变量
int rank(Matrix A, int m, int n) {
int i = 0, j = 0, k, r, u;
while(i < m && j < n) { // 当前正在处理第i个方程,第j个变量
r = i;
for(k = i; k < m; k++)
if(A[k][j]) { r = k; break; }
if(A[r][j]) {
if(r != i) for(k = 0; k <= n; k++) swap(A[r][k], A[i][k]);
// 消元后第i行的第一个非0列是第j列,且第u>i行的第j列均为0
for(u = i+1; u < m; u++) if(A[u][j])
for(k = i; k <= n; k++) A[u][k] ^= A[i][k];
i++;
}
j++;
}
return i;
}
Matrix A;
int main() {
int m = gen_primes(500);
int T;
cin >> T;
while(T--) {
int n, maxp = 0;
long long x; // 注意x的范围
cin >> n;
memset(A, 0, sizeof(A));
for(int i = 0; i < n; i++) {
cin >> x;
for(int j = 0; j < m; j++) // 求x中的prime[j]的幂,并更新系数矩阵
while(x % prime[j] == 0) {
maxp = max(maxp, j); x /= prime[j]; A[j][i] ^= 1;
}
}
int r = rank(A, maxp+1, n); // 只用到了前maxp+1个素数
cout << (1LL << (n-r))-1 << endl; // 空集不是解,所以要减1
}
return 0;
}
书上的代码:
题意:给出n个正整数,从中选出1个或者多个,使得选出来的整数乘积是完全平方数,一共有多少种选法。
思路:用01向量表示一个数,再用n个01向量来表示我们的选择,因为完全平方数要求素因子的次数一定要是偶数的,所以我们可以统计的将奇数当作1,偶数当作0,那么就是一组可以变换成oxr的方程组,最后的结果有自由变量f个,答案是2^f-1,f求解就是求n-方程组的秩