状态很差脑子不清醒了,柿子一直在推错。。。。
。。。
不难发现这个题实际上是一个完全背包
问题在于n太大了,相应的有质数的数量不会超过7个
假设要求sigema(1~plen)i pi*ci=n 的方案数
令xi=ci/(S*pi),yi=ci%(S/pi),注意yi<S/pi
则等价于sigema(1~plen)i S*xi+yi*pi=n
若令sigema(1~plen)i xi=m,则sigema(1~plen)yi*pi=n-m*S
n-m*S=sigema(1~plen)yi*pi<plen*S,可推出n/S-plen<m<=n/S
此时plen有用了,我们可以枚举m,那么对于x的方案用插板法得C(m+plen-1,plen-1),对于y直接背包plen*S,朴素的做法是O(plen*(plen*S)*S/pi)的,随便优化下就可以把S/pi去掉了,不过要稍微注意yi的限制。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; const int _=1e2; const int maxn=7*2*1e6+_; const LL mod=1e9+7; int plen,p[10]; bool divi(int n) { plen=0; for(int i=2;i*i<=n;i++) if(n%i==0) { p[0]+=i;p[++plen]=i;n/=i; if(n%i==0)return false; } if(n!=1)p[0]+=n,p[++plen]=n; return true; } LL inv[10]; void yu(){inv[1]=1;for(int i=2;i<=plen;i++)inv[i]=inv[mod%i]*(mod-mod/i)%mod;} LL C(LL n,LL m) { LL ret=1; for(int i=1;i<=m;i++) { ret=ret*(n%mod)%mod*inv[i]%mod; n--; } return ret; } LL f[2][maxn]; int now; void DP(int S) { int li=S*plen; now=0,f[now][0]=1; for(int i=1;i<=plen;i++) { now^=1; for(int j=0;j<li;j++) { f[now][j]=0; if(j-p[i]>=0)f[now][j]=(f[now][j]+f[now][j-p[i]])%mod; f[now][j]=(f[now][j]+f[now^1][j])%mod; if(j>=S/p[i]*p[i])f[now][j]=(f[now][j]-f[now^1][j-S/p[i]*p[i]]+mod)%mod; } } } int main() { freopen("3.in","r",stdin); freopen("a.out","w",stdout); int S,Q; scanf("%d%d",&S,&Q); if(!divi(S)){while(Q--)puts("0");return 0;} yu();DP(S); while(Q--) { LL n; scanf("%lld",&n);n-=p[0]; if(n<0){puts("0");continue;} LL ans=0; for(LL m=max(0LL,n/S-plen+1);m<=n/S;m++) { ans=(ans+C(m+plen-1,plen-1)*f[now][n-m*S])%mod; } printf("%lld ",ans); } return 0; }