题目连接:(C. Square Subsets)[http://codeforces.com/contest/895/problem/C]
题意:给N个范围在1~70的数找出有多少种非空子集之积是一个平方数。
题解:我们可以发现170之间只有19个质数,编号(119)。要使的某个数是个平方数肯定每个质数出现偶数次。我们可以用状压dp
先预处理1~70每个质因子出现的次数偶数为0奇数为1,比如i这个数第一个质数因子出现奇数次s[i]的最后一位为1,
状态转移方程见代码;
#include<bits/stdc++.h>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#define pb push_back
#define ll long long
#define PI 3.14159265
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define eps 1e-7
const int mod=1e9+7;
const int maxn=1e5+5;
using namespace std;
int prime[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67};
int dp[71][(1<<19)+5];
int s[100];
int c[maxn];
int cnt[75],n;
void init()
{
for(int i=1;i<=70;i++)
{
int x=i;
for(int j=0;j<19;j++)
{
while(x%prime[j]==0)
{
s[i]^=(1<<j);
x/=prime[j];
}
}
}
c[0]=1;
for(int i=1;i<=n;i++)
{
c[i]=((ll)c[i-1]*2)%mod;
}
}
int main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
init();
int a;
for(int i=0;i<n;i++)
{
cin>>a;cnt[a]++;
}
dp[0][0]=1;
for(int i=1;i<=70;i++)
{
if(!cnt[i])
{
for(int j=0;j<(1<<19);j++)
{
dp[i][j]=dp[i-1][j];
}
}
else
{
for(int j=0;j<(1<<19);j++)
{
dp[i][j]=(dp[i][j]+(ll)dp[i-1][j^s[i]]*c[cnt[i]-1])%mod;//取奇数个
dp[i][j]=(dp[i][j]+(ll)dp[i-1][j]*c[cnt[i]-1])%mod;//取偶数个
}
}
}
cout<<dp[70][0]-1<<endl;//减去全不选的情况
return 0;
}