BZOJ2655: calc(dp 拉格朗日插值)

自為風月馬前卒發表於2018-12-04

題意

題目連結

Sol

首先不難想到一個dp

(f[i][j])表示選了(i)嚴格遞增的數最大的數為(j)的方案數

轉移的時候判斷一下最後一個位置是否是(j)

[f[i][j] = f[i][j – 1] + f[i – 1][j – 1] * j]

for(int i = 0; i <= A; i++) f[0][i] = 1;
for(int i = 1; i <= N; i++)
    for(int j = 1; j <= A; j++) 
        f[i][j] = add(f[i][j - 1], mul(f[i - 1][j - 1], j));
cout << mul(f[N][A], fac[N]);

發現還是不好搞,把轉移拆開

(f[i][j] = sum_{k = 0}^{j – 1} f[i – 1][k] * (k + 1))

這個轉移就非常有意思了

我們如果把(i)看成列,(k)看成行,那麼轉移的時候實際上就是先對第(k)行乘上一個係數(k),然後再求和

如果我們把第(i – 1)列看成一個(t)次多項式,顯然第(i)列是一個(t+2)次多項式(求和算一次,乘係數算一次)

這樣的話第(i)列就是一個最高(2i+1)次多項式

插一插就好了

// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 10001;
int A, N, Lim, mod, f[501][MAXN], fac[MAXN], y[MAXN];
int add(int x, int y) {
    if(x + y < 0) return x + y + mod;
    return x + y >= mod ? x + y - mod : x + y;
}
void add2(int &x, int y) {
    if(x + y < 0) x = (x + y + mod);
    else x = (x + y >= mod ? x + y - mod : x + y);
}
int mul(int x, int y) {
    return 1ll * x * y % mod;
}
int fp(int a, int p) {
    int base = 1;
    while(p) {
        if(p & 1) base = mul(base, a);
        a = mul(a, a); p >>= 1;
    }
    return base;
}
int Large(int *y, int k) {
    static int x[MAXN], ans = 0;
    for(int i = 1; i <= Lim; i++) x[i] = i;
    for(int i = 0; i <= Lim; i++) {
        int up = y[i], down = 1;
        for(int j = 0; j <= Lim; j++) {
            if(i == j) continue;
            up = mul(up, add(k, -x[j]));
            down = mul(down, add(x[i], -x[j]));
        }
        add2(ans, mul(up, fp(down, mod - 2)));
    }
    return ans;
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("a.in", "r", stdin);
   // freopen("a.out", "w", stdout);
#endif
    cin >> A >> N >> mod; Lim = 2 * N + 1;
    fac[0] = 1; for(int i = 1; i <= N; i++) fac[i] = mul(i, fac[i - 1]);
    for(int i = 0; i <= Lim; i++) f[0][i] = 1;
    for(int i = 1; i <= N; i++) {
        for(int j = 1; j <= Lim; j++) {
            f[i][j] = add(f[i][j - 1], mul(f[i - 1][j - 1], j));
        }
    }
    for(int i = 0; i <= Lim; i++) y[i] = f[N][i];
    cout << mul(Large(y, A), fac[N]);
    return 0;
}

相關文章