Description:
M
M
种氨基酸,已知其相对分子质量分别为,经过精密的脱水缩合后形成了大量各种各样的肽链。需要预测有多少种多肽链水解后相对分子质量和为
N
N
。与
C−B−A
C
−
B
−
A
两条肽链视为不同)
Solution:
考虑把所有元素建成一个生成函数
A(x)
A
(
x
)
,那么答案就是
∑∞i=0A(x)i
∑
i
=
0
∞
A
(
x
)
i
根据无穷等比数列公式得出答案:
11−A(x)
1
1
−
A
(
x
)
多项式求逆即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 4e5 + 5, P = 1005060097;
int n, m, N, len;
ll a[maxn], b[maxn], tmp[maxn];
ll power(ll x, ll t) {
ll ret = 1;
for(; t; t >>= 1, x = x * x % P) {
if(t & 1) {
ret = ret * x % P;
}
}
return ret;
}
void ntt(ll *a, int f) {
for(int i = 0; i < N; ++i) {
int t = 0;
for(int j = 0; j < len; ++j) {
if(i >> j & 1) {
t |= 1 << (len - j - 1);
}
}
if(i < t) {
swap(a[i], a[t]);
}
}
for(int l = 2; l <= N; l <<= 1) {
int m = l >> 1;
ll w = power(5, f == 1 ? (P - 1) / l : P - 1 - (P - 1) / l);
for(int i = 0; i < N; i += l) {
ll t = 1;
for(int k = 0; k < m; ++k, t = t * w % P) {
ll x = a[i + k], y = t * a[i + m + k] % P;
a[i + k] = (x + y) % P;
a[i + m + k] = (x - y + P) % P;
}
}
}
if(f == -1) {
ll inv = power(N, P - 2);
for(int i = 0; i < N; ++i) {
a[i] = a[i] * inv % P;
}
}
}
void poly_inv(ll *a, ll *b, int l) {
if(l == 1) {
b[0] = power(a[0], P - 2);
return;
}
poly_inv(a, b, l >> 1);
N = 1;
len = 0;
while(N <= l) {
N <<= 1;
++len;
}
for(int i = 0; i < l; ++i) {
tmp[i] = a[i];
}
for(int i = l; i < N; ++i) {
tmp[i] = 0;
}
ntt(tmp, 1);
ntt(b, 1);
for(int i = 0; i < N; ++i) {
b[i] = b[i] * (2 - tmp[i] * b[i] % P + P) % P;
}
ntt(b, -1);
for(int i = l; i < N; ++i) {
b[i] = 0;
}
}
int main() {
freopen("polypeptide.in", "r", stdin);
freopen("polypeptide.out", "w", stdout);
scanf("%d%d", &n, &m);
++a[0];
for(int i = 1; i <= m; ++i) {
int x;
scanf("%d", &x);
--a[x];
}
len = 1;
while(len <= n) {
len <<= 1;
}
poly_inv(a, b, len);
printf("%lld\n", b[n]);
fclose(stdin);
fclose(stdout);
return 0;
}