CF895C Square Subsets
Petya又迟到了...老师给了他额外的任务。对于一些数组a,Petya需要找到从中间选择非空子集,使它们的乘积等于某个整数的平方的方法的数量。 如果这些方法所选择的元素的索引不同,则认为这两种是不同的方法。 因为结果可能很大,结果需要mod \; 10^9+7
考虑到完全平方数只和质因子次幂的奇偶性相关,那么我们可以把乘积转化为二进制下的异或。
于是题目变成选择若干个数异或起来为0的方案数。
那么考虑把所有元素插入到线性基中,于是不在线性基里的元素一定可以被线性基里的元素表示,相异或就可以为0。
而在线性基里的元素一定不会其他元素表示,相异或一定不为0。
所以方案数就是不在线性基中的元素个数组成的非空子集数:2^{n-cnt}-1
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
const int N = 1e5;
const int P = 1e9 + 7;
using namespace std;
int n,a[N + 5],prime[N + 5],pcnt,vis[N + 5],val[N + 5],p[N + 5],cnt;
int mypow(int a,int x){int s = 1;for (;x;x & 1 ? s = 1ll * s * a % P : 0,a = 1ll * a * a % P,x >>= 1);return s;}
void prework()
{
for (int i = 2;i <= 70;i++)
{
if (!vis[i])
prime[++pcnt] = i;
for (int j = 1;prime[j] * i <= 70 && j <= pcnt;j++)
{
vis[i * prime[j]] = 1;
if (i % prime[j] == 0)
break;
}
}
}
void ins(int x)
{
for (int i = 22;i >= 0;i--)
if (x >> i & 1)
{
if (!p[i])
{
p[i] = x;
cnt++;
break;
}
x ^= p[i];
}
}
int main()
{
scanf("%d",&n);
for (int i = 1;i <= n;i++)
scanf("%d",&a[i]);
prework();
for (int i = 1;i <= n;i++)
{
for (int j = 1;j <= pcnt;j++)
while (a[i] % prime[j] == 0)
val[i] ^= 1 << j - 1,a[i] /= prime[j];
ins(val[i]);
}
int ans = mypow(2,n - cnt) - 1;
cout<<(ans + P) % P<<endl;
return 0;
}
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步