Flink從入門到上手企業開發系列
阿新 • • 發佈:2018-12-04
Sol
首先不難想到一個dp
設f[i][j]f[i][j]表示選了ii個嚴格遞增的數最大的數為jj的方案數
轉移的時候判斷一下最後一個位置是否是jj
f[i][j]=f[i][j−1]+f[i−1][j−1]∗jf[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]=∑j−1k=0f[i−1][k]∗(k+1)f[i][j]=∑k=0j−1f[i−1][k]∗(k+1)
這個轉移就非常有意思了
我們如果把ii看成列,kk看成行,那麼轉移的時候實際上就是先對第kk行乘上一個係數kk,然後再求和
如果我們把第i−1i−1列看成一個tt次多項式,顯然第ii列是一個t+2t+2次多項式(求和算一次,乘係數算一次)
這樣的話第ii列就是一個最高2i+12i+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; }