DP - [USACO16OPEN] - 262144P

DP - [USACO16OPEN] - 262144P

\(dp[i][j]\)表示从第i个数开始,向右合成数j,最后一个用到的数(右端点)的位置

假如我们想要从第\(i\)个数开始,合成数j,首先需要\(dp[i][j-1] \neq 0\),因为只有先合成\(j-1\)才能得到\(j\)。此外,还需要\(dp[dp[i][j-1]+1][j-1] \neq 0\),这是因为,除了这一段合成\(j-1\),还需要下一段合成\(j-1\),才能将两个\(j-1\)合成一个\(j\)。因此,可知dp过程:

// init
for(int i = 1; i <= n; ++i)
  	cin >> a[i];

// init dp
for(int i = 1; i <= n; ++i)
  	dp[i][a[i]] = i;

// dp
for(int i = n; i >= 1; --i){
  	for(int j = a[i]+1; j <= 60; ++j){
      	if(dp[i][j])
    }
}

完整代码

#include <bits/stdc++.h>
using namespace std;

const int N = 262144+5;

int n;
int a[N];
int dp[N][80]; // 从第i个数开始, 向右边合成数j,得到的右端点为x

int main(){
    cin >> n;
    
    for(int i = 1; i <= n; ++i)
        cin >> a[i];
    
    for(int i = 1; i <= n; ++i){
        dp[i][a[i]] = i;
    }
    
    for(int i = n-1; i >= 1; --i){
        for(int j = a[i]+1; j <= 60; ++j){
            if(dp[i][j-1] && dp[i][j-1]+1 <= n && dp[dp[i][j-1]+1][j-1])
                dp[i][j] = dp[dp[i][j-1]+1][j-1];
        }
    }

    int ans = 0;

    
    for(int j = 1; j <= 60; ++j){
        for(int i = 1; i <= n; ++i){
            if(dp[i][j]){
                ans = max(ans, j);
                break;
            }
        }
    }

    cout << ans << endl;
    return 0;
}

posted @ 2021-04-14 16:27  popozyl  阅读(52)  评论(0编辑  收藏  举报