题目链接:https://www.luogu.com.cn/problem/P5366
给出一个n,G,L。
q次询问在1∼n中选择若干个数字并且数字x必选,要求这些数的gcd为G且lcm为L的方案数。
1≤n,G,L,x≤108,1≤q≤105
我们令m=LG,x=xG,n=⌊nG⌋,那么就是求选1∼m中的数的情况下gcd=1,lcm=m的方案。
发现对于每个m的分解后的质因数pc,我们选择的数的为pk,那么我们至少需要一个k=0和一个k=c。
也就是其实0<k<m的都是不会对这个质因数产生影响的,所以我们可以把一个质因子p分出两个状态,分别是k=0的和k=m的有没有。
同样的,我们用上面的状态S表示1∼n的数字,会发现S最多只有六百出头种不同的取值。
那么我们把这些取值拿出来,把数字分成不同的类,这样我们就只需要考虑每个类的数字个数了。记fi,S表示做完了前i类时状态为S的方案,同理gi,S则表示做完了后i类。
这样我们可以用FWT快速处理出hi,S表示处理了除了第i类以外的所有类,状态为S时的方案。
然后再考虑这一类有一个数字必选来转移每个hi,S就知道每一类的答案了。
#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;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构