1. 程式人生 > >Codeforces Round #462 (Div. 1)A. A Twisty Movement()

Codeforces Round #462 (Div. 1)A. A Twisty Movement()

題目傳送門 題目大意: 問題描述 給你一個僅包含數字1,2且長度為n的序列a[1…n]. 現在,你可以選擇一個區間l,r(1<=l<=r<=n),然後翻轉a[l…r]裡面的數字. *比如a={4,5,6},那麼翻轉a[2…3]之後,a={4,6,5}. *你可以選擇讓l==r,那麼這個時候a陣列沒有發生變化. *設1<=x1< x2< …< xk<=n,且a[x1]<=a[x2]<=…<=a[xk],那麼a[x1],a[x2],…,a[xk]就稱為一個不下降子序列,k就是這個不下降子序列的長度. 請你選取合適的l,r使得產生的新的序列,它的最長不下降子序列的值最大. 你的任務是輸出這個最大值. 輸入格式 第一行一個正整數n(1<=n<=2000),表示序列的長度. 第二行有n個整數,第i個數字代表ai(1<=ai<=2). 輸出格式 輸出只有一個整數,對於給定的序列,請輸出題中所要求的最大值. 樣例 樣例輸入 4 1 2 1 2 樣例輸出 4 樣例輸入2 10 1 1 2 2 2 1 1 2 2 1 樣例輸出2 9 樣例解釋 對於第一個樣例,翻轉[2,3]這個區間,陣列會變成[1,1,2,2].此時最長不下降子序列的長度為4,嘗試其他[l,r]的賦值,發現最長不下降子序列的值都不會大於4. 提示 注意只會出現1,2這兩個數字. 題解:求出1的字首和,2的字尾和,以及區間[i,j]的最長不遞增子序列。 dp[i][j][0]表示區間i-j以1結尾的最長不遞增子序列; dp[i][j][1]表示區間i-j以2結尾的最長不遞增子序列,顯然是區間i-j2的個數; 所以轉移方程為: dp[i][j][1] = dp[i][j-1][1] + (a[j]==2); dp[i][j][0] = max(dp[i][j-1][0], dp[i][j-1][1]) + (a[j]==1);(1<=i<=n,i<=j<=n) 程式碼如下:

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int maxn=2000+10;
int arr[maxn];
int q1[maxn],h2[maxn];
int dp[maxn][maxn][2];
int main() {
    int n, t;
    cin>>n;
    for(int i=1; i<=n; i++)  {//
        cin>>arr[i];
        q1[i]+=q1[i-1]+(arr[i]==1);
    }
    for(int i=n; i>=1; i--)  {
        h2[i]=h2[i+1]+(arr[i]==2);
    }
    int ans=-1000000;
    for(int i=1;i<=n;i++) {
        for(int j=i;j<=n;j++) {
            //cout<<"------"<<endl;
            dp[i][j][1] = dp[i][j-1][1]+(arr[j]==2);
            dp[i][j][0] = max(dp[i][j-1][0], dp[i][j-1][1])+(arr[j]==1);
            ans=max(ans,dp[i][j][1]+q1[i-1]+h2[j+1]);
            ans=max(ans,dp[i][j][0]+q1[i-1]+h2[j+1]);
        }
    }
    cout<<ans<<endl;
}