codeforces #462 D - A Twisty Movement - dp

终于我也开始做dp题了。
链接


做法1:
s = [ 0 , 1 , 2 , 1 , 2 ] , i 指数组 a 的下标, t y p e 指数组 s 的下标,均从1开始。

状态转移方程为:

d p [ t y p e ] [ i ] = max { d p [ t y p e 1 ] [ i ] , d p [ t y p e ] [ i 1 ] + ( a [ i ] = ? s [ t y p e ] ) }
,表示区间 [ 1 , i ] 中形如 1 , , 2 , , 1 , , 1 的子序列的最大长度。

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 2e3+7;
int a[maxn];
int dp[5][maxn];
int s[] = {0,1,2,1,2};
int main(){
    ios::sync_with_stdio(0);
    int n;cin >> n;
    for(int i = 1;i<=n;i++){
        cin >> a[i];
    }
    for(int i = 1;i<=n;i++){
        for(int type = 1;type<=4;type++){
            dp[type][i] = max(dp[type-1][i],dp[type][i-1]+(a[i] == s[type]));
        }
    }
    cout << dp[4][n] << endl;
}

做法2:

状态转移方程:

d p [ i ] [ j ] [ 2 ] = d p [ i ] [ j 1 ] [ 2 ] + ( a [ j ] = ? 2 )
,表示区间 [ i , j ] 中以2结尾的 不增子序列(形如 [ 2 , 2 , 1 , 1 ] )的长度。

d p [ i ] [ j ] [ 1 ] = max { d p [ i ] [ j 1 ] [ 1 ] , d p [ i ] [ j 1 ] [ 2 ] } + ( a [ j ] = ? 1 )
,表示区间 [ i , j ] 中以1结尾的 不增子序列(形如 [ 1 , 1 , 1 , 1 ] )的长度。

s u m 1 [ i ] 为前缀1的数量。 s u m 2 [ i ] 为后缀2的数量。

可以用方程的特性,去掉 d p [ ] 的两个维度。

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 2e3+7;
int a[maxn];
int dp[3];
int sum1[maxn],sum2[maxn];
int main(){
    ios::sync_with_stdio(0);
    int n;cin >> n;
    for(int i = 1;i<=n;i++){
        cin >> a[i];
    }
    for(int i = 1;i<=n;i++){
        sum1[i] += sum1[i-1] + (a[i] == 1);
    }
    for(int i = n;i>=1;i--){
        sum2[i] += sum2[i+1] + (a[i] == 2);
    }
    int ans = -1e9;
    for(int i = 1;i<=n;i++){
        memset(dp,0,sizeof(dp));
        for(int j = i;j<=n;j++){
            dp[1] = max(dp[1],dp[2]) + (a[j] == 1);
            dp[2] = dp[2] + (a[j] == 2);
            ans = max(ans,sum1[i-1]+sum2[j+1]+dp[1]);
            ans = max(ans,sum1[i-1]+sum2[j+1]+dp[2]);
        }
    }
    cout << ans << endl;
}

猜你喜欢

转载自blog.csdn.net/lanadeus/article/details/79346157