小皮球在计算出答案之后,买了一堆皮肤,他心里很开心,但是一不小心,就忘记自己买了哪些皮肤了。==|||万
幸的是,他还记得他把所有皮肤按照1~N来编号,他买来的那些皮肤的编号(他至少买了一款皮肤),最大公约数
是G,最小公倍数是L。现在,有Q组询问,每组询问输入一个数字X,请你告诉小皮球,有多少种合法的购买方案中
,购买了皮肤X?因为答案太大了,所以你只需要输出答案mod1000000007即可。
标签:答案 memcpy str ons 一个 最小 公倍数 oid get
如果L%G非零则无解,将L的每个质因子看作一维,只有每维都取到最小(L中对应质数的次数)和最大幂次(G中对应质数的次数),才能得到对应的G和L,状压表示每一维的质因数次数是否取到最小/大值,可以选的数一定每维幂次在最小值和最大值之间,这样的数很少,在数据范围内不超过800个,分治dp得出某个数不选的方案数,用总方案数减去即得到某个数必选的方案数。时间复杂度为O((L的约数个数)*log(L的约数个数)*4^(L的不同质因子个数))
#include<bits/stdc++.h> typedef int mat[259][259]; const int P=1e9+7; int _(){ int x=0,c=getchar(); while(c<48)c=getchar(); while(c>47)x=x*10+c-48,c=getchar(); return x; } int n,g,l,qp,mx,fs[107],tg[107],tl[107],fp=0,ans[807]; inline void inc(int&a,int b){a+=b-P,a+=a>>31&P;} struct dat{ int v,s1,s2; bool operator<(const dat&w)const{return v<w.v;} void trans(mat a){ for(int i=mx-1;i>=0;--i){ int*m1=a[i],*m2=a[i|s1]; for(int j=mx-1;j>=0;--j)inc(m2[j|s2],m1[j]); } } }vs[807]; int vp=0; void f1(int x){ for(int i=2;i*i<=x;++i)if(x%i==0){ do x/=i;while(x%i==0); fs[fp++]=i; } if(x>1)fs[fp++]=x; } void f2(int x,int*t){ for(int i=0;i<fp;++i)for(;x%fs[i]==0;x/=fs[i],++t[i]); } void dfs(int w,int v,int s1,int s2){ if(w==fp){ if(v<=n)vs[++vp]=(dat){v,s1,s2}; return; } for(int i=0;i<=tl[w];++i,v*=fs[w]){ if(i>=tg[w])dfs(w+1,v,s1|(i==tg[w])<<w,s2|(i==tl[w])<<w); } } mat F[27]; int Fp=0,all; void cpy(){ for(int i=0;i<mx;++i)memcpy(F[Fp+1][i],F[Fp][i],sizeof(int)*mx); ++Fp; } void solve(int L,int R){ if(L==R){ if(R==1){ cpy(); vs[1].trans(F[Fp]); all=F[Fp][mx-1][mx-1]; --Fp; } ans[L]=((all-F[Fp][mx-1][mx-1])%P+P)%P; return; } int M=L+R>>1; cpy(); for(int i=M+1;i<=R;++i)vs[i].trans(F[Fp]); solve(L,M); --Fp; cpy(); for(int i=L;i<=M;++i)vs[i].trans(F[Fp]); solve(M+1,R); --Fp; } void nos(){ while(qp--)puts("0"); exit(0); } int main(){ n=_(),g=_(),l=_(),qp=_(); f1(g),f1(l); std::sort(fs,fs+fp); fp=std::unique(fs,fs+fp)-fs; f2(g,tg),f2(l,tl); if(n<g)nos(); for(int i=0;i<fp;++i)if(tg[i]>tl[i])nos(); dfs(0,1,0,0); std::sort(vs+1,vs+vp+1); mx=1<<fp; F[0][0][0]=1; solve(1,vp); while(qp--){ int x=_(),w=std::lower_bound(vs+1,vs+vp+1,(dat){x})-vs; if(w<=vp&&vs[w].v==x)printf("%d\n",ans[w]); else puts("0"); } return 0; }
标签:答案 memcpy str ons 一个 最小 公倍数 oid get
原文地址:http://www.cnblogs.com/ccz181078/p/7501689.html