【FWT】【复杂度玄学】BZOJ5019[Snoi2017]遗失的答案

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/88907140

分析:

至今仍然不知道。。。为什么N以内的,是L的因数且是G的倍数的数不超过1000个。。。

缸道理不应该是 N \sqrt N 个吗。。。

看来是我孤陋寡闻了。。。。

合并的时候用一下FWT

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 1010
#define MAXS 65556
#define MOD 1000000007
#define MAXQ 100010
using namespace std;
void Read(int &x){
	char c;
	while(c=getchar(),c!=EOF&&(c<'0'||c>'9'));
	x=c-'0';
	while(c=getchar(),c!=EOF&&c>='0'&&c<='9')
		x=x*10+c-'0';	
}
map<int,int> f;
vector<int> pr,tp;
int N,G,L,Q;
int a[MAXQ],fac[MAXN];
int dp1[MAXN][MAXS],dp2[MAXN][MAXS],res[MAXS*4];
int masks[MAXN],n;
int ans[MAXN];
void FWT(int A[],int N){
	for(int i=1;i<N;i<<=1)
		for(int j=0;j<N;j+=(i<<1))
			for(int k=0;k<i;k++){
				A[i+j+k]=A[i+j+k]+A[j+k];	
				if(A[i+j+k]>=MOD)
					A[i+j+k]-=MOD;
			}
}
void IFWT(int A[],int N){
	for(int i=1;i<N;i<<=1)
		for(int j=0;j<N;j+=(i<<1))
			for(int k=0;k<i;k++){
				A[i+j+k]=A[i+j+k]-A[j+k];
				if(A[i+j+k]<0)
					A[i+j+k]+=MOD;
			}
}
void Mul(int A[],int B[],int N,int M,int res[]){
//	int p=1;
//	while(p<=N+M)
//		p<<=1;
	FWT(A,N);
	FWT(B,N);
	for(int i=0;i<N;i++)
		res[i]=1ll*A[i]*B[i]%MOD;
	IFWT(res,N);
}
int main(){
	SF("%d%d%d",&N,&G,&L);
	SF("%d",&Q);
	for(int i=1;i<=Q;i++)
		Read(a[i]);
//		SF("%d",&a[i]);
	if(L%G){
		for(int i=1;i<=Q;i++)
			PF("0\n");	
		return 0;
	}
	L/=G,N/=G;
	for(int i=1;1ll*i*i<=1ll*L;i++)
		if(L%i==0){
			if(i<=N)
				fac[++n]=i;
			if(L/i<=N&&i*i!=L)
				fac[++n]=L/i;
		}
	sort(fac+1,fac+1+n);
	for(int i=1;i<=n;i++)
		f[fac[i]]=i;
	for(int i=2;1ll*i*i<=1ll*L;i++)
		if(L%i==0){
			pr.push_back(i);
			int tot=0;
			while(L%i==0){
				tot++;
				L/=i;	
			}
			tp.push_back(tot);
		}
	if(L!=1){
		pr.push_back(L);
		tp.push_back(1);	
	}
	int m=pr.size();
	for(int i=1;i<=n;i++){
		int val=fac[i];
		for(int j=0;j<m;j++){
			if(val%pr[j]==0){
				int tot=0;
				while(val%pr[j]==0){
					tot++;
					val/=pr[j];	
				}
				if(tot==tp[j])
					masks[i]|=(1<<(2*j+1));
			}
			else
				masks[i]|=(1<<(2*j));
		}
	}
	dp1[0][0]=1;
	for(int i=0;i<n;i++)
		for(int j=0;j<(1<<(2*m));j++){
			(dp1[i+1][j|masks[i+1]]+=dp1[i][j])%=MOD;	
			(dp1[i+1][j]+=dp1[i][j])%=MOD;	
		}
	dp2[n+1][0]=1;
	for(int i=n+1;i>=2;i--)
		for(int j=0;j<(1<<(2*m));j++){
			(dp2[i-1][j|masks[i-1]]+=dp2[i][j])%=MOD;
			(dp2[i-1][j]+=dp2[i][j])%=MOD;
		}
	for(int i=1;i<=n;i++){
		Mul(dp1[i-1],dp2[i+1],(1<<(2*m)),(1<<(2*m)),res);
		for(int j=0;j<(1<<(2*m));j++)
			if((j|masks[i])==(1<<(2*m))-1)
				(ans[i]+=res[j])%=MOD;
	}
	for(int i=1;i<=Q;i++){
		if(a[i]%G){
			PF("0\n");
			continue;
		}
		else
			a[i]/=G;
		if(f.count(a[i])==0)
			PF("0\n");
		else{
			PF("%d\n",ans[f[a[i]]]);
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/88907140