Codeforces Round #100 E. New Year Garland (第二類斯特林數+dp)
阿新 • • 發佈:2017-12-19
using 情況 inline 顏色不同 force jai 相同 其中 problem
那麽,\(dp[i][j] = \sum\limits_{i = 1}^{m}\sum\limits_{j = 1 }^{l[i]} [dp[i-1][j]*(繩子i上放j 種小球的合法方案數)-(繩子i與繩子i-1用同樣小球的方案數)(i > 1)(j <= l[i-1])]\)
題目鏈接:
http://codeforces.com/problemset/problem/140/E
題意:
聖誕樹上掛彩球,要求從上到下掛\(n\)層彩球。已知有\(m\)種顏色的球,球的數量不限。
要求結果對\(p\)取模。然後給你\(n\)個數,表示第 \(i\) 根繩長 \(l_i\),也就是要掛 \(l_i\) 個球。
\(1.\)要求每根繩上相鄰彩球顏色不同。
\(2.\)相鄰的繩子上掛的彩球種類不能相同。
題解:
我們先解決子問題,先考慮第 \(i\) 層上能放多少個球,\(a[i][j]\)表示長為\(i\)的繩子上放\(j\)種球的方案數,考慮的其實就是\(j\)種小球往\(i\)個無編號的盒子裏放,每個盒子放一個,相鄰盒子小球不一樣,
\(a[i?1][j?1]\)表示\(i?1\)個盒子放\(j?1\)種小球,變成 \(i\) 盒子 \(j\)小球,就是新添加一個小球放進一個新的盒子裏。
\(a[i?1][j]\)表示\(i?1\)個盒子\(j\)種小球,新添加一個盒子時可以放除了相鄰盒子中的小球外任意小球,即 \((j?1)\) 個。
所以,\(a[i][j]=a[i?1][j?1]+a[i?1][j]?(j?1)\)。顯然這就是第二類斯特林數。
我們再考慮 \(dp[i][j]\)表示在第\(1\)到\(i?1\)根繩子排列合法的情況下,第\(i\)根繩子用 \(j\) 種小球的合法方案數。
那麽,\(dp[i][j] = \sum\limits_{i = 1}^{m}\sum\limits_{j = 1 }^{l[i]} [dp[i-1][j]*(繩子i上放j 種小球的合法方案數)-(繩子i與繩子i-1用同樣小球的方案數)(i > 1)(j <= l[i-1])]\) 。
所以,
繩子\(i\)上放\(j\)種小球的合法情況有: \(a[i][j]*A_k^j\) (其中\(k\) 為可以選擇的顏色數量)。
繩子\(i\)與繩子\(i-1\)用同樣小球的方案數就是:\(dp[i-1][j]*a[i][j]*A_j^j\)。
最後把該預處理的都預處理一下就可以了。
\(dp\) 那個數組好難開。。。最後\(resize\)一下過了....沒有\(c++11\)我可能啥都寫不出來....
代碼:
#include<bits/stdc++.h> using namespace std; const double pi = acos(-1.0); const double eps = 1e-9; const int maxn = 1001000; int l[maxn],a[5201][5201],fac[5201],rfac[5201]; //int dp[5201][5201]; std::vector<int> dp[maxn]; int main(int argc, char const *argv[]) { int n,m,p; std::cin >> n >> m >> p; int sz = 0 ; for(int i=1;i<=n;i++) { std::cin >> l[i]; //sz = max(l[i],sz); dp[i].resize(l[i]+1); } // vector<vector<int>> dp(sz + 1, vector<int>(sz + 1, 0)); fac[0] = 1; rfac[0] = 1; for(int i=1;i<=5010;i++) { fac[i] = 1LL * fac[i-1] * i % p; rfac[i] = 1LL * rfac[i-1] * (m - i + 1) % p ; } a[0][0] = 1; for(int i=1;i<=5010;i++) { for(int j=1;j<=i;j++) { a[i][j] = (a[i-1][j-1] + 1LL * a[i-1][j] * (j-1) % p) % p; } } int sum = 1; int ans = 0; for(int i=1;i<=n;i++) { for(int j=1;j<=l[i];j++) { dp[i][j] = 1LL * sum * rfac[j] % p * a[l[i]][j] % p; if(i > 1 && j <= l[i-1]) { dp[i][j] = (dp[i][j] - 1LL * dp[i-1][j] * a[l[i]][j] % p * fac[j] % p + p) % p; } ans = (ans + dp[i][j]) % p; } sum = ans; ans = 0; } std::cout << sum << '\n'; return 0; }
Codeforces Round #100 E. New Year Garland (第二類斯特林數+dp)