CF895C 平方子序列——线性基+压位

Description

给定n序列An,从序列中选若干个数,使得乘积为完全平方数,有多少种方案。
两个方案不同仅当选择的位置不同。方案数对1e9+7取模。

Input

第一行一个整数n,n<=100000
第二行n个整数表示Ai,Ai<=70

Output

输出方案数对1e9+7取模后的值

Sample Input

4

1 1 1 1

Sample Output

15

Hint

Sample input2
4
2 2 2 2
Sample output2
7

Sample input3
1
36
Sample output3
1

由线性基的性质,选出最大线性无关组以后,任选不属于无关组的元素后都能构成合法的方案,因此答案为pow(2,n-m)-1,其中,m为无关组的秩即大小

对于个数而言:3^3*3与3^5*3等价,类似的:

由唯一分解定理n=p1^k1……pm^km,我们预处理出1~70每个数包含的质因数,显然,若数n含偶数个数质因子p,则p可以忽略,因此我们只用记录每个数所含有的奇数个的质因子,注意到1~70只有19个质数,直接压位即可

#include
using namespace std;
#define Inc(i,L,r) for(register int i=(L);i<=(r);++i)
#define Red(i,r,L) for(register int i=(r);i>=(L);--i)
#define ll long long
#define Mod (int)(1e9+7)
int pri[]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67};//70以内的质数
int n,fac[77];
struct Linear_Basis{
	int p[37];
	inline bool insert(int k){
		Red(i,31,0){
			if(!(k>>i))continue;
			if(!p[i]){p[i]=k;break;}
			k^=p[i];
		}
		return k>0;
	}
}xxj;
inline void init(){
	Inc(i,1,70){ 
		int Fk=i;
		Inc(j,1,19){
			int num=0;
			for(;Fk%pri[j]==0;Fk/=pri[j])++num;
			if(num&1)fac[i]|=(1<<(j-1));//压位,表示i有没有pri[j]这个质因数且个数为奇数
		}
	}
}
inline ll Quick(ll x,int k){
	ll ans=1;
	while(k){
		if(k&1)ans=ans*x%Mod;
		k>>=1;
		(x*=x)%=Mod;
	}
	return ans;
}
inline void solv(){
	scanf("%d",&n);
	int num=0;
	Inc(i,1,n){
		int idx;scanf("%d",&idx);
		if(xxj.insert(fac[idx]))++num;
	}
	cout<<(Quick(2,n-num)%Mod-1)%Mod<<"\n";
}
int main(){
	init();
	solv();
	return 0;
} 

 

 

 

 

 

你可能感兴趣的:(数学,线性基)