题解 P5850 【calc加强版】
出题人来补上题解 qwq Latex 已重写。
公式可能显示有锅,建议到博客中查看。
首先注意到题目中
而此时的答案显然
取对数把乘法变加法,即
这里有
故有
则
自然数幂和可以用某种方法(插值、伯努利数之类)算出来。
最后还要多项式 exp,直接
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 505;
int n, M, P, inv[N], Bo[N], C[N][N], a[N], b[N];
typedef vector<int> poly;
poly F[N];
int calc(const poly&a, int x)
{
int y = 0;
for(int i = a.size() - 1; i >= 0; i --)
y = (1LL * y * x + a[i]) % P;
return y;
}
int main()
{
scanf("%d%d%d",&M,&n,&P);
for(int i = 0; i <= n + 1; i ++)
{
C[i][0] = 1;
for(int j = 1; j <= i; j ++)
C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % P;
}
inv[1] = 1;
for(int i = 2; i <= n + 1; i ++)
inv[i] = (ll) inv[P % i] * (P - P / i) % P;
Bo[0] = 1;
for(int i = 1; i <= n; i ++)
{
int t = 0;
for(int j = 0; j < i; j ++)
t = (t + (ll)Bo[j] * C[i + 1][j]) % P;
Bo[i] = (ll)(P - inv[i + 1]) * t % P;
}
F[0] = poly{0, 1};
for(int i = 1; i <= n; i ++)
{
F[i].resize(i + 2);
for(int j = 1; j <= i + 1; j ++)
{
F[i][j] = (ll) Bo[i + 1 - j] * C[i + 1][j] % P * inv[i + 1] % P;
if((i + 1 - j) & 1)
F[i][j] = (P - F[i][j]) % P;
}
}
for(int i = 1; i <= n; i ++)
{
a[i] = (ll)inv[i] * calc(F[i], M) % P;
if(~i&1) a[i] = (P - a[i]) % P;
}
for(int i = 1; i <= n; i ++)
a[i - 1] = (ll)i * a[i] % P;
b[0] = 1;
for(int i = 1; i <= n; i ++)
{
for(int j = 0; j < i; j ++)
b[i] = (b[i] + (ll)b[j] * a[i - j - 1]) % P;
b[i] = (ll)b[i] * inv[i] % P;
}
int ans = b[n];
for(int i = 2; i <= n; i ++) ans = (ll)ans * i % P;
printf("%d", ans);
return 0;
}
注意到复杂度瓶颈在于对所有
多项式求逆即可,整个复杂度也是
代码需要把上面代码的暴力改成多项式全家桶。