正题
题目链接:https://www.luogu.com.cn/problem/P5366
题目大意
给出一个n,G,Ln,G,Ln,G,L。
qqq次询问在1∼n1\sim n1∼n中选择若干个数字并且数字xxx必选,要求这些数的gcdgcdgcd为GGG且lcmlcmlcm为LLL的方案数。
1≤n,G,L,x≤108,1≤q≤1051\leq n,G,L,x\leq 10^8,1\leq q\leq 10^51≤n,G,L,x≤108,1≤q≤105
解题思路
我们令m=LG,x=xG,n=⌊nG⌋m=\frac{L}{G},x=\frac{x}{G},n=\lfloor\frac{n}{G}\rfloorm=GL,x=Gx,n=⌊Gn⌋,那么就是求选1∼m1\sim m1∼m中的数的情况下gcd=1,lcm=mgcd=1,lcm=mgcd=1,lcm=m的方案。
发现对于每个mmm的分解后的质因数pcp^cpc,我们选择的数的为pkp^kpk,那么我们至少需要一个k=0k=0k=0和一个k=ck=ck=c。
也就是其实0<k<m0<k<m0<k<m的都是不会对这个质因数产生影响的,所以我们可以把一个质因子ppp分出两个状态,分别是k=0k=0k=0的和k=mk=mk=m的有没有。
同样的,我们用上面的状态SSS表示1∼n1\sim n1∼n的数字,会发现SSS最多只有六百出头种不同的取值。
那么我们把这些取值拿出来,把数字分成不同的类,这样我们就只需要考虑每个类的数字个数了。记fi,Sf_{i,S}fi,S表示做完了前iii类时状态为SSS的方案,同理gi,Sg_{i,S}gi,S则表示做完了后iii类。
这样我们可以用FWTFWTFWT快速处理出hi,Sh_{i,S}hi,S表示处理了除了第iii类以外的所有类,状态为SSS时的方案。
然后再考虑这一类有一个数字必选来转移每个hi,Sh_{i,S}hi,S就知道每一类的答案了。
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cctype>
using namespace std;
const int N=1<<16,M=610,P=1e9+7;
int n,G,L,q,m,tot,cnt,MS,num[N];
int p[99],c[99],pos[N],pw[M],rev[M];
int f[M][N],g[M][N],h[M][N];
int read(){int x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-')f=-f;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+c-48;c=getchar();}return x*f;
}
int power(int x,int b){int ans=1;while(b){if(b&1)ans=1ll*ans*x%P;x=1ll*x*x%P;b>>=1;}return ans;
}
void FWT(int *f,int n,int op){for(int p=2;p<=n;p<<=1)for(int k=0,len=p>>1;k<n;k+=p)for(int i=k;i<k+len;i++)(f[i+len]+=f[i]*op)%=P;return;
}
void dfs(int dep,int x,int s){if(x>n)return;if(dep>cnt){num[s]++;return;}dfs(dep+1,x,s|(1<<dep+cnt-1));for(int i=1,pw=1;i<=c[dep];i++)pw=pw*p[dep],dfs(dep+1,x*pw,s|((i==c[dep])<<dep-1));return;
}
void init(){int x=m;for(int i=2;i<=x;i++)if(x%i==0){p[++cnt]=i;while(x%i==0)c[cnt]++,x/=i;}dfs(1,1,0);MS=(1<<cnt*2);for(int i=0;i<MS;i++)if(num[i]){pos[i]=++tot;rev[tot]=i;pw[tot]=power(2,num[i])-1;}f[0][0]=g[tot+1][0]=1;for(int i=1;i<=tot;i++)for(int j=0;j<MS;j++){(f[i][j]+=f[i-1][j])%=P;(f[i][j|rev[i]]+=1ll*f[i-1][j]*pw[i]%P)%=P;}for(int i=tot;i>=1;i--)for(int j=0;j<MS;j++){(g[i][j]+=g[i+1][j])%=P;(g[i][j|rev[i]]+=1ll*g[i+1][j]*pw[i]%P)%=P;}for(int i=0;i<=tot;i++)FWT(f[i],MS,1);for(int i=1;i<=tot+1;i++)FWT(g[i],MS,1);for(int i=1;i<=tot;i++)for(int j=0;j<MS;j++)h[i][j]=1ll*f[i-1][j]*g[i+1][j]%P;for(int i=1;i<=tot;i++){FWT(h[i],MS,-1);int k=power(2,num[rev[i]]-1);for(int j=MS-1;j>=0;j--){int r=h[i][j];h[i][j]=0;(h[i][j|rev[i]]+=1ll*r*k%P)%=P;}}return;
}
signed main()
{n=read();G=read();L=read();q=read();n/=G;m=L/G;init();while(q--){int x=read();if(x%G){puts("0");continue;}if(L%x){puts("0");continue;}x/=G;if(x>n){puts("0");continue;}int S=((1<<cnt)-1)*(1<<cnt);for(int i=1;i<=cnt;i++)if(x%p[i]==0){int k=0;S^=(1<<i+cnt-1);while(x%p[i]==0)x/=p[i],k++;if(k==c[i])S|=(1<<i-1);}cout<<(h[pos[S]][MS-1]+P)%P<<'\n';}return 0;
}