题目传送门
分析:
首先分析一下性质:
首先,S一定不含某个质数的平方,这里可以特判
p就是所有S的质因数,并且每一个都要出现
那么我们可以先求和sum
n就变成n-sum,那么就可以不要求所有质数一定出现了
再者,质数的种类数会很少,不会超过10
我们设每个质数pi的出现次数为ci
由于pi一定为S的因数,所以pici可以表示为pi(a(S/pi)+b)=aS+bpi
其中ci就分解为a(S/pi)+b了
前半部分相当于凑齐一个S要用哪一种pi,对于每一种pi,我们使用隔板法选择
后半部分的b由于小于S/pi很小,可以直接考虑完全背包
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define MOD 1000000007
using namespace std;
inline long long getint()
{
long long num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
int S,Q;
int p[10],cnt,num;
long long f[2][15000005],now=1,pre;
long long sum[15000005],inv[10],n;
inline long long C(long long p,long long q)
{
long long ret=1;p%=MOD;
for(int i=1;i<=q;i++)ret=ret*(p-i+1)%MOD*inv[i]%MOD;
return ret;
}
int main()
{
S=getint(),Q=getint();
int tmp=S;
for(int i=2;i*i<=tmp;i++)
if(tmp%i==0)
{
p[++cnt]=i,tmp/=i;
if(tmp%i==0)
{
while(Q--)printf("0
");
return 0;
}
}
if(tmp>1)p[++cnt]=tmp;
for(int i=1;i<=cnt;i++)num+=p[i];
inv[1]=inv[0]=1;
for(int i=2;i<=cnt;i++)inv[i]=1ll*(MOD-MOD/i)*inv[MOD%i]%MOD;
f[pre][0]=1;
for(int i=1;i<=cnt;i++,swap(now,pre))
{
for(int j=0;j<p[i];j++)sum[j]=f[now][j]=f[pre][j];
for(int j=p[i];j<=S*i;j++)
{
int k=j%p[i];
if(j>=S)sum[k]=(sum[k]-f[pre][j-S]+MOD)%MOD;
sum[k]=(sum[k]+f[pre][j])%MOD;
f[now][j]=sum[k];
}
}
while(Q--)
{
n=getint()-num;
long long ans=0;
for(int i=0;i<cnt;i++)
{
if(n<i*S)break;
ans=(ans+f[pre][i*S+n%S]*C(n/S-i+cnt-1,cnt-1))%MOD;
}
printf("%lld
",(ans+MOD)%MOD);
}
}