[lnsyoj895C/luoguCF895C] Square Subsets
题意
给出一个序列 ,求满足乘积是完全平方数的非空子集个数和。
sol
由于完全平方数一定需要满足质因数的个数均为偶数,所以可以设 表示某个数的质因数个数是奇数还是偶数,合并时用异或即可。
考虑一种稍暴力的写法:设 表示到 时,子集乘积状态为 的方案个数,设 表示数 对应的状态。
容易得出 ,其中前者为选择该数,后者为不选择该数。
状态数不可接受。
考虑到值域为 ,因此有很多重复的数,而这些数的顺序并无关联,因此考虑变更状态为 表示到数 时,子集乘积状态为 的方案个数。
假设对于某个数,数列中有 个,那么选择偶数个这个数的方案数为
奇数同理为 ,因此 ,其中前者为选择奇数个,后者为选择偶数个。
代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 75, M = 25, K = 1 << 19, S = 100005, mod = 1e9 + 7;
int cnt[N], state[N];
int primes[M] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67};
int n;
int pow2[S];
int f[N][K];
int main(){
scanf("%d", &n);
pow2[0] = 1;
for (int i = 1; i <= n; i ++ ) {
int t;
scanf("%d", &t);
cnt[t] ++ ;
pow2[i] = (LL) pow2[i - 1] * 2 % mod;
}
for (int i = 1, k = 1; i <= 70; i ++ , k = i)
for (int j = 0; j < 19; j ++ )
if (k % primes[j] == 0)
while (k % primes[j] == 0)
state[i] ^= 1 << j, k /= primes[j];
f[0][0] = 1;
int lst = 0;
for (int i = 1; i <= 70; i ++ ) {
if (!cnt[i]) continue;
for (int s = 0; s < K; s ++ ) {
int ns = s ^ state[i];
f[i][s] = (LL) f[lst][s] * pow2[cnt[i] - 1] % mod;
f[i][s] = (f[i][s] + (LL) f[lst][ns] * pow2[cnt[i] - 1] % mod) % mod;
}
lst = i;
}
printf("%d\n", (f[lst][0] - 1 + mod) % mod);
}
分类:
题解 / 2025训练
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App