题目大意
一个序列a1,...,an 是合法的,当且仅当:
1. 长度为给定的n。
2.
3. a1,...,an互不相等。
一个序列的值定义为它里面所有数的乘积,即a1a2...an。
现在的问题是给定n,A,mod,求所有不同合法序列的值的和(两个序列不同当且仅当他们任意一位不一样)。并且答案对一个数mod 取余的结果。
A≤109
n≤500
mod≤109且为质数
解题思路
显然我们可以强制是ai>ai−1,然后再把最后的答案乘n!。
一个很直接的思路就是设F[i][j]表示用了前i个数中的
F[i][j]=F[i−1][j−1]∗j+F[i−1][j]
这个的复杂度是O(An)的。我们发现这个算法的瓶颈主要在于A太大,所以我们考虑一种把关于
首先考虑只用到F[A]的信息时关于[A,2A]的数求积的问题,我们发现
∏(ai+A)=∑s⊂0...n−1An−|s|∗∏i∈sai
意思就是对于每个(ai+A)我们都可以选择用乘ai还是A,然后乘
gi=∑j=0iAi−j∗fj∗(A−ji−j)
其实很好理解这里的fj其实就等于上面式子的∏i∈sai,而组合数的意义就是对于上面的(ai+A)除了j个选了
(A−ji−j)=∏k=1i−jA−j+1−kk=∏i−1k=j(A−k)(i−j)!
令mi=∏i−1k=0(A−i),rmi=(mi)−1,那么(A−ji−j)=(i−j)!−1∗mi∗rmj
最后gi的表达式就是
gi=mi∑j=0iAi−j∗fj∗rmj∗(i−j)!−1
让f和
F[2A][i]=∑j=0ifj∗gi−j
边界比较麻烦,要稍微处理一下。然后像快速乘一样,我们就可以做O(log)次得到F[A],而每次的复杂度是n2,总的复杂度就是O(n2logA)。
程序
//YxuanwKeith
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 505;
struct Dp {
int dp[MAXN];
};
int Mo, A, N, M[MAXN], InvM[MAXN], Pow[MAXN], Inv[MAXN], Fac[MAXN];
int Power(int x, int y) {
int Ans = 1;
for (; y; y >>= 1, x = 1ll * x * x % Mo)
if (y & 1) Ans = 1ll * Ans * x % Mo;
return Ans;
}
Dp Double(Dp Now, int A) {
Dp Ans;
memset(Ans.dp, 0, sizeof Ans.dp);
static int G[MAXN];
M[0] = Pow[0] = InvM[0] = 1;
for (int i = 0; i < N; i ++) M[i + 1] = 1ll * M[i] * (A - i) % Mo;
for (int i = 1; i <= N; i ++) InvM[i] = Power(M[i], Mo - 2);
for (int i = 1; i <= N; i ++) Pow[i] = 1ll * Pow[i - 1] * A % Mo;
G[0] = 1;
for (int i = 1; i <= N; i ++) {
int Sum = 0;
for (int j = 0; j <= i; j ++) {
Sum = (Sum + 1ll * Pow[i - j] * Now.dp[j] % Mo * InvM[j] % Mo * Inv[i - j] % Mo) % Mo;
}
G[i] = 1ll * M[i] * Sum % Mo;
}
for (int i = 0; i <= N; i ++) {
Ans.dp[i] = 0;
for (int j = 0; j <= i; j ++)
Ans.dp[i] = (Ans.dp[i] + 1ll * Now.dp[j] * G[i - j] % Mo) % Mo;
}
return Ans;
}
Dp Single(Dp Now, int A) {
Dp Ans;
Ans.dp[0] = 1;
for (int j = 1; j <= N; j ++)
Ans.dp[j] = (1ll * Now.dp[j - 1] * A % Mo + Now.dp[j]) % Mo;
return Ans;
}
Dp Solve(int y) {
Dp Now;
if (!y) {
memset(Now.dp, 0, sizeof Now.dp);
Now.dp[0] = 1;
return Now;
}
Now = Double(Solve(y / 2), y / 2);
if (y & 1) Now = Single(Now, y);
return Now;
}
void Prepare() {
Fac[0] = Inv[0] = 1;
for (int i = 1; i <= N; i ++) Fac[i] = 1ll * Fac[i - 1] * i % Mo;
for (int i = 1; i <= N; i ++) Inv[i] = Power(Fac[i], Mo - 2);
}
int main() {
scanf("%d%d%d", &A, &N, &Mo);
Prepare();
printf("%d\n", 1ll * Solve(A).dp[N] * Fac[N] % Mo);
}