平方数肯定满足所有质数的次幂都是偶数,具体数值我们不关心只关心奇偶。
由于a[i]的取值是1-70,我们发现1-70中质数有19个
于是我们可以用 (1<<19)-1 个状态表示这19个质数的幂次是奇数还是偶数
由于所有集合都是由空集扩展而来。
我们设dp的初状态dp[0][0]为 没有处理数时,所有质数次幂为偶数时 的个数 是1.
由于数加入顺序对组成最终集合的个数没有影响:
我们枚举i从1到70 dp[i][j]表示处理到i时,状态为j时,集合的个数。
转移时:
对数值i的个数cnt进行讨论(zt[i]为 i的状态 即:19个质数的次幂的状态压缩)
当cnt为奇数时:dp[i][j]=dp[i-1][j^zt[i]]*x
x=C(1,cnt)+C(3,cnt)+………… +C(cnt,cnt)=2^(cnt-1)
同理,当cnt为偶数时
dp[i][j]=dp[i-1][j]*x
x=C(2,cnt)+C(4,cnt)+………… +C(cnt,cnt)=2^(cnt-1)
转移式出来了,初状态dp[0][0]=1表示空集.
末状态dp[n][0]表示所有子集中 满足所有质数的幂次都是偶数的个数 即题意要求的。
减去1 空集 即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef __int128 LL;
//typedef unsigned long long ull;
//#define F first
//#define S second
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ld,ld> pdd;
const ld PI=acos(-1);
const ld eps=1e-9;
//unordered_map<int,int>mp;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
//#define a(i,j) a[(i)*(m+2)+(j)] //m是矩阵的列数
//pop_back()
const int seed=131;
const int M = 1e5+7;
const int mod =1e9+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y,int z){ee[++cnt].nxt=head[x],ee[cnt].to=y,ee[cnt].val=z,head[x]=cnt;}
*/
ll dp[2][(1<<19)+7];
ll a[M],b[M];
int prime[100],id[100],sz,zt[72];
int p[30],c[30];
ll h[M];
ll qpow(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b/=2;
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
ll n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i],b[a[i]]++;
for(int i=2;i<=70;i++)
{
bool f=true;
for(int j=2;j<=sqrt(i);j++)
if(i%j==0)f=false;
if(f)prime[++sz]=i,id[i]=sz;
}
h[0]=1;
for(int i=1;i<=n;i++)h[i]=h[i-1]*2%mod;
zt[1]=0;
for(int i=2;i<=70;i++)
{
ll ans=0;
int tp=i;
for(int j=2;j<=tp;j++)
{
if(tp%j==0)
{
int z=0;
while(tp%j==0)tp/=j,z++;
z=z%2;
ans+=(1<<(id[j]-1))*z;
}
}
zt[i]=ans;
}
// cout<<"ok"<<endl;
dp[0&1][0]=1;
for(int i=1;i<=70;i++)
{
int tp=zt[i];
if(b[i]==0)
{
for(int j=0;j<(1<<sz);j++)dp[i&1][j]=dp[(i-1)&1][j];
continue;
}
for(int j=0;j<(1<<sz);j++)
{
dp[i&1][j]=dp[(i-1)&1][j^tp]*h[b[i]-1]%mod;
dp[i&1][j]=(dp[i&1][j]+dp[(i-1)&1][j]*h[b[i]-1])%mod;
}
// cout<<i<<" "<<dp[i][0]<<" "<<dp[i][1]<<" "<<dp[i][4]<<" "<<dp[i][5]<<endl;
}
ll ans=(dp[70&1][0]-1+mod)%mod;//有一种空集的情况
cout<<ans<<endl;
return 0;
}