[BZOJ2655]calc(DP + 拉格朗日插值)
阿新 • • 發佈:2019-01-13
Address
Solution
- 顯然我們有個 DP
- 表示選出 個無序的, 內的互不相同的整數的所有方案乘積之和
- 轉移方程就是考察,這 個數是否包含有 ,來進行轉移
- 答案就是
- 然後你會發現在 和 的資料規模下, 的樸素 DP 和 的矩陣乘法都過不去
- 我們大膽猜想 是關於 的多項式
- 可以得到
- 設 的最高次數為
- 那麼 的次數顯然為
- 而 相當於是 的字首和
- 而一個多項式求字首和後次數總是會加
- 所以
- 而 是常數 ,次數為
- 所以 ,即 是 次多項式
- 取 , , , , 這 個多項式點值
- 通過拉格朗日插值求出
- 複雜度
Code
// luogu-judger-enable-o2
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
const int N = 1005;
int A, n, ZZQ, f[N][N];
int qpow(int a, int b)
{
int res = 1;
while (b)
{
if (b & 1) res = 1ll * res * a % ZZQ;
a = 1ll * a * a % ZZQ;
b >>= 1;
}
return res;
}
int Lagrange(int A)
{
int i, j, res = 0;
For (i, 0, (n << 1))
{
int x1 = 1, x2 = 1;
For (j, 0, (n << 1)) if (j != i)
{
x1 = 1ll * x1 * (A - j + ZZQ) % ZZQ;
x2 = 1ll * x2 * (i - j + ZZQ) % ZZQ;
}
res = (1ll * x1 * qpow(x2, ZZQ - 2) % ZZQ *
f[n][i] + res) % ZZQ;
}
For (i, 1, n) res = 1ll * res * i % ZZQ;
return res;
}
int main()
{
int i, j;
std::cin >> A >> n >> ZZQ;
For (j, 0, (n << 1)) f[0][j] = 1;
For (i, 1, n) For (j, 1, (n << 1))
f[i][j] = (1ll * j * f[i - 1][j - 1] + f[i][j - 1]) % ZZQ;
std::cout << Lagrange(A % ZZQ) << std::endl;
return 0;
}