题解
显然可以发现,只有 为无平方因子数才可能有解。假设 , 均为质数。那么 (前 小的质数乘起来一定大于 )。那么问题就是把 拆成 有多少种方案。 表示 种质数取了多少次。
首先 ,所以可以先把 减去 ,如果为负就肯定无解。
然后发现 肯定为 的约数,那么每个 都可以写成$X\cdot S+Y\cdot a_i的形式。
假设 ,
有 ,其中
知道
,那么用完全背包预处理左边的部分。
然后
的拆分直接组合数插板法就行了。
注意完全背包为了保证 的范围要减去 ,即 的情况。
见代码
CODE
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 2000005;
const int mod = 1e9 + 7;
int S, q, m, p[MAXN], cnt, a[10], s, f[20000005], inv[10];
bool vis[MAXN];
LL n;
inline int C(LL N, LL M) {
int re = 1;
for(int i = 1; i <= M; ++i)
re = 1ll * re * ((N-i+1)%mod) % mod * inv[i] % mod;
return re;
}
int main () {
freopen("prime.in", "r", stdin);
freopen("prime.out", "w", stdout);
inv[0] = inv[1] = 1;
for(int i = 2; i < 10; ++i) inv[i] = 1ll*(mod-mod/i)*inv[mod%i]%mod;
scanf("%d%d", &S, &q); int s = S;
for(int i = 2; i <= S; ++i) {
if(!vis[i]) p[++cnt] = i;
for(int j = 1; j <= cnt && p[j]*i <= S; ++j) {
vis[p[j]*i] = 1;
if(i % p[j] == 0) break;
}
}
for(int i = 1; i <= cnt; ++i)
if(S % p[i] == 0) a[++m] = p[i], s /= p[i];
bool flg = 0;
if(s > 1) flg = 1;
else {
s = 0;
for(int i = 1; i <= m; ++i) s += a[i];
f[0] = 1;
for(int i = 1; i <= m; ++i) {
for(int j = a[i]; j <= i*S; ++j) (f[j] += f[j-a[i]]) %= mod;
for(int j = i*S; j >= S; --j) (f[j] -= f[j-S]) %= mod;
}
}
while(q--) {
scanf("%lld", &n);
if(flg) puts("0");
else {
n -= s;
if(n < 0) puts("0");
else {
int ans = 0;
for(int i = 0; i <= m && i*S <= n; ++i)
ans = (ans + 1ll * f[i*S + n%S] * C((n-i*S)/S+m-1, m-1)) % mod;
printf("%d\n", (ans + mod) % mod);
}
}
}
}