Description:
一个序列
a1,...,an
a
1
,
.
.
.
,
a
n
是合法的,当且仅当:
长度为给定的
n
n
。
都是
[1,A]
[
1
,
A
]
中的整数。
a1,...,an
a
1
,
.
.
.
,
a
n
互不相等。
一个序列的值定义为它里面所有数的乘积,即
a1a2...an
a
1
a
2
.
.
.
a
n
。
求所有不同合法序列的值的和。
两个序列不同当且仅当他们任意一位不一样。
输出答案对一个数
mod
m
o
d
取余的结果。
Solution:
考虑一个暴力的
dp,dp[i][j]
d
p
,
d
p
[
i
]
[
j
]
表示前
i
i
个数选个数。
那么转移即为
dp[i][j]=dp[i−1][j]+dp[i−1][j−1]∗i∗j
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
]
+
d
p
[
i
−
1
]
[
j
−
1
]
∗
i
∗
j
表示选或不选,并且枚举插入的位置。
由于这个
dp
d
p
式是一个
2∗n
2
∗
n
的多项式,所以我们插值求第
A
A
项即可。
注意插值如果从开始要插到
2∗n+1
2
∗
n
+
1
次。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1005;
int n, A, P;
ll pre[maxn], suf[maxn], inv[maxn], dp[maxn][maxn];
ll calc(ll *f, ll u, int n) {
pre[0] = 1;
suf[n + 2] = 1;
for(int i = 1; i <= n + 1; ++i) {
pre[i] = pre[i - 1] * (u - i + P) % P;
}
for(int i = n + 1; i; --i) {
suf[i] = suf[i + 1] * (u - i + P) % P;
}
ll ret = 0, tmp;
for(int i = 1; i <= n + 1; ++i) {
tmp = f[i] * pre[i - 1] % P * suf[i + 1] % P * inv[i - 1] % P * inv[n - i + 1] % P;
if((n - i + 1) & 1) {
tmp = P - tmp;
}
ret = (ret + tmp) % P;
}
return ret;
}
int main() {
scanf("%d%d%d", &A, &n, &P);
inv[0] = inv[1] = 1;
for(int i = 2; i < maxn; ++i) {
inv[i] = (P - P / i) * inv[P % i] % P;
}
for(int i = 2; i < maxn; ++i) {
inv[i] = inv[i] * inv[i - 1] % P;
}
dp[0][0] = 1;
for(int j = 1; j <= 2 * n + 1; ++j) {
for(int i = 0; i <= n; ++i) {
dp[i][j] = (dp[i][j] + dp[i][j - 1]) % P;
if(i) {
dp[i][j] = (dp[i][j] + dp[i - 1][j - 1] * i % P * j % P) % P;
}
}
}
if(A <= 2 * n) {
printf("%lld\n", dp[n][A]);
} else {
printf("%lld\n", calc(dp[n], A, 2 * n));
}
return 0;
}