zoukankan      html  css  js  c++  java
  • 「SNOI2017」遗失的答案

    「SNOI2017」遗失的答案

    传送门

    Loj

    题解

    首先可以考虑把(n ightarrow n/G,L ightarrow L/G),这是很显然的.

    然后考虑所有可能出现的质因数就是(L)的质因数,所以可以对(L)进行质因数分解.

    接着考虑设(f_{S1,S2})表示最小集为(S1),最大集为(S2)的状态的方案数,这个很显然可以(dp).

    这个时候我们需要强制一个数字在里面,相当于是强制他不在里面然后查他的超集的方案数.

    所以可以前后缀(dp)然后做一个(FMT),求出来每一个不在里面的方案数,最后做一个超集和就可以了.

    代码

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<queue>
    #include<set>
    #include<map>
    #include<iostream>
    using namespace std;
    #define ll long long
    #define REP(a,b,c) for(int a=b;a<=c;a++)
    #define re register
    #define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
    typedef pair<int,int> pii;
    #define mp make_pair
    inline int gi()
    {
    	int f=1,sum=0;char ch=getchar();
    	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return f*sum;
    }
    const int N=10010,LIM=1<<16,MX=18,Mod=1e9+7,INV=500000004;
    int n,G,L,Q,prime[N],s,p[N],mx[N],tot,cnt[LIM];
    bool is_prime[N];
    void init()
    {
    	is_prime[1]=1;
    	for(int i=2;i<=10000;i++)
    	{
    		if(!is_prime[i])prime[++s]=i;
    		for(int j=1;j<=s&&prime[j]*i<=10000;j++)
    		{
    			is_prime[prime[j]*i]=1;
    			if(!(i%prime[j]))break;
    		}
    	}
    }
    void calc(int x)
    {
    	for(int i=1;i<=s;i++)
    		if(x%prime[i]==0)
    		{
    			p[++tot]=prime[i];
    			while(x%prime[i]==0)x/=prime[i],mx[tot]++;
    		}
    	if(x>1)p[++tot]=x,mx[tot]=1;
    }
    void dfs(int d,int s,int S1,int S2)
    {
    	if(d>tot){cnt[S1|(S2<<tot)]++;return;}
    	for(int i=0;i<=mx[d];i++)
    	{
    		dfs(d+1,s,S1|(i==0?1<<(d-1):0),S2|(i==mx[d]?1<<(d-1):0));
    		if(s*p[d]>n)break;
    		s*=p[d];
    	}
    }
    int o[LIM],S[LIM],suf[810][LIM],pre[810][LIM],f[LIM],tmp[LIM];
    int qpow(int a,int b){int ret=1;while(b){if(b&1)ret=1ll*ret*a%Mod;b>>=1;a=1ll*a*a%Mod;}return ret;}
    void FMT(int *a,int limit,int opt)
    {
    	for(int i=1;i<limit;i<<=1)
    		for(int R=i<<1,j=0;j<limit;j+=R)
    			for(int k=0;k<i;k++)
    				if(opt==1)a[i+j+k]=(a[i+j+k]+a[j+k])%Mod;
    				else a[i+j+k]=(a[i+j+k]-a[j+k]+Mod)%Mod;
    }
    void FAT(int *a,int limit,int opt)
    {
    	for(int i=1;i<limit;i<<=1)
    		for(int R=i<<1,j=0;j<limit;j+=R)
    			for(int k=0;k<i;k++)
    				if(opt==1)a[j+k]=(a[j+k]+a[i+j+k])%Mod;
    				else a[j+k]=(a[j+k]-a[i+j+k]+Mod)%Mod;
    }
    int get(int x)
    {
    	int S1=0,S2=0;
    	for(int i=1;i<=tot;i++)
    	{
    		int cnt=0;
    		while(x%p[i]==0)x/=p[i],cnt++;
    		if(cnt==0)S1|=1<<(i-1);
    		if(cnt==mx[i])S2|=1<<(i-1);
    	}
    	return S1|(S2<<tot);
    }
    int main()
    {
    	n=gi();G=gi();L=gi();Q=gi();init();
    	if(L%G){while(Q--)puts("0");return 0;}
    	L/=G;n/=G;calc(L);dfs(1,1,0,0);int lim=1<<(tot<<1);s=0;
    	for(int i=0;i<lim;i++)
    		if(cnt[i])o[++s]=i,S[s]=qpow(2,cnt[i])-1;
    	for(int i=1;i<=s;i++)cnt[i]=S[i];
    	f[0]=1;pre[0][0]=1;
    	for(int i=1;i<=s;i++)
    	{
    		int x=o[i];
    		for(int j=0;j<lim;j++)
    			tmp[j|x]=(tmp[j|x]+1ll*f[j]*cnt[i]%Mod)%Mod;
    		for(int j=0;j<lim;j++)f[j]=(f[j]+tmp[j])%Mod,tmp[j]=0;
    		for(int j=0;j<lim;j++)pre[i][j]=f[j];
    	}
    	memset(f,0,sizeof(f));
    	f[0]=1;suf[s+1][0]=1;
    	for(int i=s;i;i--)
    	{
    		int x=o[i];
    		for(int j=0;j<lim;j++)
    			tmp[j|x]=(tmp[j|x]+1ll*f[j]*cnt[i]%Mod)%Mod;
    		for(int j=0;j<lim;j++)f[j]=(f[j]+tmp[j])%Mod,tmp[j]=0;
    		for(int j=0;j<lim;j++)suf[i][j]=f[j];
    	}
    	for(int i=0;i<=s;i++)FMT(pre[i],lim,1);
    	for(int i=1;i<=s+1;i++)FMT(suf[i],lim,1);
    	for(int i=0;i<=s;i++)
    		for(int j=0;j<lim;j++)
    			pre[i][j]=1ll*pre[i][j]*suf[i+2][j]%Mod;
    	for(int i=0;i<=s;i++)FMT(pre[i],lim,-1),FAT(pre[i],lim,1);
    	while(Q--)
    	{
    		int x=gi();
    		if(x%G){puts("0");continue;}
    		x/=G;
    		if(L%x||x>n){puts("0");continue;}
    		int ss=get(x),p=lower_bound(o+1,o+s+1,ss)-o-1;
    		int v=pre[p][(lim-1)^ss];
    		printf("%lld
    ",1ll*v*(cnt[p+1]+1)%Mod*INV%Mod);
    	}
    	return 0;
    }
    
  • 相关阅读:
    第四次团队作业
    第三次团队作业博客——系统设计
    第二次团队作业博客
    第一次团队作业博客
    团队作业——总结
    软件工程课程总结
    Beta冲刺提交-星期三
    个人作业-Alpha项目测试
    第四次团队作业
    第三次团队作业——系统设计
  • 原文地址:https://www.cnblogs.com/fexuile/p/12846046.html
Copyright © 2011-2022 走看看