题目传送门
题意:给n个数,选择一些数字乘积为平方数的选择方案数。训练指南题目。
分析:每一个数字分解质因数。比如4, 6, 10, 15,, , , , 令,表示选择第i个数字,那么,如果p是平方数,那么每个质因数上的指数为偶数,x1系数为2已经是偶数不考虑。可以转换为异或为0判断偶数,即奇数置为1,偶数置为0,然后n个数字m个质因数的增广矩阵消元看有几个自由变量(取0或1无所谓),答案是2^r - 1(全部都不取方案不算)
#include <bits/stdc++.h>const int N = 500 + 5;
bool vis[N];
int prime[N];
int A[N][105];void sieve(int n) {int m = sqrt (n + 0.5);for (int i=2; i<=m; ++i) {if (!vis[i]) {for (int j=i*2; j<=n; j+=i) {vis[j] = true;}}}
}int gen_prime(int n) {memset (vis, false, sizeof (vis));sieve (n);int c = 0;for (int i=2; i<=n; ++i) {if (!vis[i]) {prime[c++] = i;}}return c;
}int rank(int m, int n) {int i = 0, j = 0;while (i < m && j < n) {int r = i;for (int k=i; k<m; ++k) {if (A[k][j]) {r = k;break;}}if (A[r][j]) {if (r != i) {//!for (int k=0; k<=n; ++k) {std::swap (A[r][k], A[i][k]);}}for (int k=i+1; k<m; ++k) {if (A[k][j]) {for (int c=i; c<=n; ++c) {A[k][c] ^= A[i][c];}}}++i;}++j;}return i;
}//Running_Time
int main() {int T; scanf ("%d", &T);int m = gen_prime (500);while (T--) {int n; scanf ("%d", &n);memset (A, 0, sizeof (A));int maxp = 100;for (int i=0; i<n; ++i) {long long x; scanf ("%lld", &x);for (int j=0; j<m; ++j) {while (x % prime[j] == 0) {x /= prime[j];A[j][i] ^= 1;maxp = std::max (maxp, j);}}}int r = rank (maxp+1, n);std::cout << ((1LL << (n - r)) - 1) << '\n';}return 0;
}