BZOJ3462 DZY Loves Math II
首先如果\(S\)中含平方因子或者\(\sum p>x\),直接输出\(0\)
之后我们令\(x\)减去\(\sum p\),之后就变成了一个完全背包问题
背包的体积那么大可咋搞啊
我们注意到对于一个质数\(p_i\),其能表示的数是\(aS+bp_i(bp_i<S)\)的形式,两种方案不同当且仅当存在一个质数\(a\)不同或\(b\)不同,于是我们可以对于两部分分别计算乘法原理合并就好了
由于质因子个数不会超过\(7\),所以所有质数\(bp_i\)的总和不会超过\(7\times S\),我们对这部分跑一个多重背包;对于一个询问\(x\),我们枚举一下这一部分取得总和是多少,剩下的肯定是\(S\)的整数倍,用组合数分配一下就好了
代码
#include<bits/stdc++.h>
#define re register
#define LL long long
const int mod=1e9+7;
int m,S,Q,Sum,Sz,ans;LL n;
int pre[14000005],dp[14000005];
int f[200005],p[100005],Pr[105],inv[105];
inline int dqm(int x) {return x<0?x+mod:x;}
inline int qm(int x) {return x>=mod?x-mod:x;}
inline int C(LL n,int m) {
if(m>n) return 0;
int nw=inv[m];
for(re LL i=n;m;--i,--m) nw=1ll*nw*(i%mod)%mod;
return nw;
}
int main() {
scanf("%d%d",&S,&Q);int R=sqrt(S)+1;m=S;
for(re int i=2;i<=R;i++) {
if(!f[i]) p[++p[0]]=i;
for(re int j=1;j<=p[0]&&p[j]*i<=R;++j) {
f[p[j]*i]=1;if(i%p[j]==0) break;
}
}
for(re int i=1;i<=p[0];i++) {
if(S==1) break;if(S%p[i]) continue;
S/=p[i];if(S%p[i]==0) {while(Q--)puts("0");return 0;}
Pr[++Pr[0]]=p[i];Sum+=p[i];
}
if(S!=1) Pr[++Pr[0]]=S,Sum+=S;dp[0]=1;
for(re int i=1;i<=Pr[0];++i) {
Sz+=m-Pr[i];
for(re int j=0;j<=Sz;++j) {
if(j>=Pr[i]) pre[j]=qm(pre[j-Pr[i]]+dp[j]);else pre[j]=dp[j];
dp[j]=dqm(pre[j]-(j<m?0:pre[j-m]));
}
}
inv[0]=inv[1]=1;for(re int i=2;i<=Pr[0];++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for(re int i=2;i<=Pr[0];++i) inv[i]=1ll*inv[i]*inv[i-1]%mod;
for(;Q;--Q,ans=0) {
scanf("%lld",&n);if(n<Sum) {puts("0");continue;}n-=Sum;
for(re int i=n%m,tot=0;i<=n&&i<=Sz;i+=m,++tot)
ans=qm(ans+1ll*dp[i]*C(n/m-tot-1+Pr[0],Pr[0]-1)%mod);
printf("%d\n",ans);
}
return 0;
}