Description
给 (n(1le nle 10^5)) 个数 (a_i(1le a_ile 70)) 。求非空子集的个数,满足子集中所有的数的积是一个完全平方数。
Solution
因为 (a_ile 70) ,所以我们预处理质因子。二进制 (sta[i]) 的第 (j) 位表示 (i) 这个数(不是 (a_i) )分解后是否含第 (j) 个质数的奇数次方。
于是 (dp[i][j]) 表示 ([1,i]) 里的数取出一些乘积为状态 (j) 的方案数。转移见代码。
#include<bits/stdc++.h>
using namespace std;
#define N 100001
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define ll long long
inline int read() {
int x = 0, flag = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') flag = -1;
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0'; return x * flag;
}
const int P = 1e9 + 7;
const int prime[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67 };
int n, bar[75], sta[75], bin[N] = { 1 }, dp[75][(1 << 19) + 5];
int main() {
cin >> n; rep(i, 1, n) bar[read()]++;
rep(i, 1, 70) {
int t = i;
rep(j, 0, 18) while (t % prime[j] == 0) sta[i] ^= (1 << j), t /= prime[j];
}
rep(i, 1, n) bin[i] = (bin[i - 1] * 2) % P;
dp[0][0] = 1;
rep(i, 1, 70) rep(j, 0, (1 << 19) - 1)
if (bar[i] == 0) dp[i][j] = dp[i - 1][j];
else
dp[i][j ^ sta[i]] = (dp[i][j ^ sta[i]] + (ll)dp[i - 1][j] * bin[bar[i] - 1]) % P,
dp[i][j] = (dp[i][j] + (ll)dp[i - 1][j] * bin[bar[i] - 1]) % P;
cout << dp[70][0] - 1;
return 0;
}