BZOJ 4221 [JOI2012春季合宿]Kangaroo (DP)
題目鏈接
https://www.lydsy.com/JudgeOnline/problem.php?id=4221
題解
orz WYC 爆切神仙DP
首先將所有袋鼠按大小排序。考慮從前往后DP, 設(shè)\(f[i][j]\)表示前\(i\)個元素形成了\(j\)條鏈。
然而需要處理“套到不能套為止”的問題,因此再加一維: \(k\)表示目前有多少個元素確定了必須要套后面的袋鼠。
設(shè)\(cnt[i]\)表示有多少個別的袋鼠能套\(i\). 那么從\(i-1\)轉(zhuǎn)移到\(i\)時\(k\)的范圍是\([0,cnt[i]-(i-j-1)]\), 因為前\((i-1)\)個袋鼠形成了\(j\)條鏈,有\((i-j-1)\)個袋鼠已經(jīng)套上了,由于袋鼠是從大到小排的,那么能套上\(i\)之前的袋鼠就能套\(i\), 因此\((i-j-1)\)就是能套上\(i\)且套了的袋鼠個數(shù),\(cnt[i]-(i-j-1)\)就是能套上\(i\)且還沒套的袋鼠個數(shù)。
轉(zhuǎn)移:
(1) 這個點作為鏈的起點。這樣會導致任何沒套上袋鼠的袋鼠都要再套一個比\(i\)小的袋鼠,因此轉(zhuǎn)移到\(dp[i][j+1][cnt[i]-(i-j-1)]\).
(2) 插入到一個鏈的末尾。這個鏈有可能是必須要套后面的袋鼠也有可能不是。乘上相應(yīng)的系數(shù)轉(zhuǎn)移即可。
時間復雜度\(O(n^3)\).
據(jù)說有神仙\(O(n^2)\)做法……哪位大爺教教我啊
代碼
#include<bits/stdc++.h> #define llong long long using namespace std;const int N = 300; const int P = 1e9+7; struct Element {int a,b;bool operator <(const Element &arg) const {return a>arg.a;} } a[N+3]; int cnt[N+3]; llong dp[2][N+3][N+3]; int n;void updsum(llong &x,llong y) {x = (x+y)%P;}int main() {scanf("%d",&n);for(int i=1; i<=n; i++) scanf("%d%d",&a[i].a,&a[i].b);sort(a+1,a+n+1);for(int i=1; i<=n; i++) {for(int j=1; j<i; j++) {if(a[j].b>a[i].a) cnt[i]++;}}dp[0][0][0] = 1ll; int cur = 0,nxt = 1;for(int i=1; i<=n; i++){memset(dp[nxt],0,sizeof(dp[nxt]));for(int j=0; j<=i; j++){for(int k=0; k<=cnt[i]-(i-j-1); k++){if(dp[cur][j][k]){updsum(dp[nxt][j][k],dp[cur][j][k]*(cnt[i]-(i-j-1)-k));if(k) {updsum(dp[nxt][j][k-1],dp[cur][j][k]*k);}updsum(dp[nxt][j+1][cnt[i]-(i-j-1)],dp[cur][j][k]);}}}cur^=1,nxt^=1;}llong ans = 0ll;for(int i=0; i<=n; i++) {ans = (ans+dp[cur][i][0])%P;}printf("%lld\n",ans);return 0; }總結(jié)
以上是生活随笔為你收集整理的BZOJ 4221 [JOI2012春季合宿]Kangaroo (DP)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LOJ #2731 [JOI2016春季
- 下一篇: BZOJ 4388 [JOI2012春季