P3205 [HNOI2010] 合唱队

P3205 [HNOI2010] 合唱队

题目翻译:

太简单了,就不翻译了

思路:

一道很不像区间\(dp\)的区间\(dp\),我们知道,不管是理想队形,还是初始队形,其大小都为\(n\),那我们令\(i,j\)表示已经加入的队形在最终队形的\(i\)\(j\)中则令\(f[i][j][0]\)表示把点从左边加入第\(i\)人,而\(f[i][j][1]\)表示将第\(j\)人从右边加入。由此可以推出三种情况:

先令第\(i\)个人的高度为\(h[i]\)

\(1.\)若上一个人是第\(i+1\)个,则有\(h[i]<h[i+1]\)那也就是说它比上一个人矮,那就应该加到右边。

\[$dp[i][j][0]+=dp[i+1][j][0] (h[i]<h[i+1])$ \]

\(2.\)若上一个人是\(j\)那它上次就是从右边加入,而\(h[i]<h[j]\),则它比上一个矮,那它就应该从左边加入,则:

\[$dp[i][j][0]+=dp[i+1][j][1] (h[i]<h[j])$ \]

\(3.\)若上一个人是\(j-1\)而我的高度\(h[j]>h[j-1]\),那我比上一个高,就应该从右边加入,则:

\[$dp[i][j][1]+=dp[i][j-1][1] (h[j-1]<h[j])$ \]

\(4.\)若上一个人是\(i\),且我的高度\(h[j]>h[i]\)则我还是因该从右边加入,则

\[$dp[i][j][1]+=dp[i][j-1][0] (h[j]>h[i])$ \]

为了保证\(dp\)时所有子区间已经\(dp\),则我们根据长度\(dp\)即可

完整代码:

#include<bits/stdc++.h>
using namespace std;
const int N=2000;
const int P=19650827;
int dp[N][N][2];
int h[N];
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>h[i];
        dp[i][i][0]=1;
    }
    for(int len=1;len<=n;len++){
        for(int i=1;i<=n-len+1;i++){
            int j=i+len-1;
            if(h[i]<h[i+1])dp[i][j][0]+=dp[i+1][j][0];
            if(h[i]<h[j])dp[i][j][0]+=dp[i+1][j][1];
            if(h[j]>h[i])dp[i][j][1]+=dp[i][j-1][0];
            if(h[j]>h[j-1])dp[i][j][1]+=dp[i][j-1][1];
            dp[i][j][0]%=P;
            dp[i][j][1]%=P;
        }
    }
    cout<<(dp[1][n][0]+dp[1][n][1])%P<<endl;
}

区间\(DP\)讲解

posted @ 2025-01-20 19:30  XichenOC  阅读(119)  评论(0)    收藏  举报