Description
我们称一个数nnn的S−S-S−质数拆分满足以下条件:
1.p1+p2+p3+p4+...+pk=n1.p1+p2+p3+p4+...+pk=n1.p1+p2+p3+p4+...+pk=n
2.p1<=p2<=p3<=p4<=...<=pk2.p1<=p2<=p3<=p4<=...<=pk2.p1<=p2<=p3<=p4<=...<=pk
3.p是质数3.p是质数3.p是质数
4.lcm(p1,p2,p3,p4,...,pk)=S4.lcm(p1,p2,p3,p4,...,pk)=S4.lcm(p1,p2,p3,p4,...,pk)=S
给出SSS,qqq个nnn,回答每个nnn的S−S-S−质数拆分。
Sample Input
30 3
9
29
1000000000000000000
Sample Output
0
9
450000036
首先如果SSS由平方质因子就ngngng
可以得知是让你求由SSS的若干个质因子组成nnn方案数。
先把nnn减掉所有质因子的和去掉只出现一次的限制。
然后这是一个很好的模型。
求:p1c1+p2c2+p3c3+p4c4+...+pkck=np1c1+p2c2+p3c3+p4c4+...+pkck=np1c1+p2c2+p3c3+p4c4+...+pkck=n
对于一个每一个质因子 的cicici,可以表示为:ci=ai∗(S/pi)+bici=ai*(S/pi)+bici=ai∗(S/pi)+bi。
对于一个nnn它肯定是由若干个前面那一部分和若干个后面的部分组成的。
枚举前面部分的大小,可以将前面的部分用一个组合数算出。
后面的部分可以预处理一个多重背包,背包的大小不超过k∗Sk*Sk∗S,且对于每一个i,bi<cii,bi<cii,bi<ci。
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const LL mod = 1e9 + 7;
LL read() {
LL s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
void put(int x) {
if(x >= 10) put(x / 10);
putchar(x % 10 + '0');
}
LL inv, f[2][7 * 2000001], sum[2000001];
int S, q, now, plen, p[10];
LL pow_mod(LL a, int k) {
LL ans = 1;
while(k) {
if(k & 1) (ans *= a) %= mod;
(a *= a) %= mod; k /= 2;
} return ans;
}
void add(LL &x, LL y) {
y -= y >= mod ? mod : 0;
x += y;
x -= x >= mod ? mod : 0;
}
LL C(LL n, LL m) {
if(n < m) return 0;
LL ans = 1, hh = 1;
for(LL i = n; i >= n - m + 1; i--) (ans *= i % mod) %= mod;
return ans * inv % mod;
}
void pre() {
inv = 1;
for(int i = 1; i < plen; i++) (inv *= i) %= mod;
inv = pow_mod(inv , mod - 2);
now = 0; f[now][0] = 1;
for(int i = 1; i <= plen; i++) {
now ^= 1;
for(int j = 0; j < p[i]; j++) sum[j] = 0;
for(int j = 0; j <= i * S - p[i]; j++) {
if(j >= S) add(sum[j % p[i]], mod - f[now ^ 1][j - S]);
add(sum[j % p[i]], f[now ^ 1][j]);
f[now][j] = sum[j % p[i]];
}
}
}
int main() {
S = read(), q = read();
int dd = S;
for(int i = 2; i <= sqrt(dd); i++) if(dd % i == 0){
dd /= i; p[++plen] = i;
if(dd % i == 0) {while(q--) puts("0"); return 0;}
} if(dd > 1) p[++plen] = dd;
int sum = 0; pre();
for(int i = 1; i <= plen; i++) sum += p[i];
while(q--) {
LL n = read() - sum;
if(n < 0) {puts("0"); continue;}
LL k = n % S, q = n / S;
int ans = 0;
for(LL i = q; q - i < plen && i >= 0; i--)
(ans += f[now][n - i * S] * C(i + plen - 1, plen - 1) % mod) %= mod;
put(ans), puts("");
} return 0;
}