【DP合集】合并 union

给出一个 1 ∼ N 的序列 A ( A 1 , A 2 , ..., A N ) 。你每次可以将两个相邻的元素合并,合并后的元素权值即为 这两个元素的权值之和。求将 A 变为一个非降序列,最少需要多少步操作。

Input

输入的第一行一个整数 N ( N ≤ 5000) 。 
接下来一行 N 个整数,描述序列 A 。保证序列 A 中的每个元素的值不超过 1000 。

Output

输出一行一个整数,表示最少的操作数。

 
题解:
区间dp真的难,(。・∀・)ノ゙嗨!
好了,设dp[i][j]表示从区间把前j个数,把区间i~j合并后满足单调的元素数量,我们可以考虑,统计一个前缀和sum,然后枚举
三个端点i,j,k,我们是想把i~j压缩成一个数,然后k在i之前,找到元素数量最少的,进行转移,转移条件 是sum[i]-sum[k-1]<=sum[j]-sum[i]
代码:
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<cstring>
const int MAXN=5100; 
using namespace std;
int dp[MAXN][MAXN],sum[MAXN],ans=-1;
 
void cl(){
    memset(dp,0,sizeof(dp));
    memset(sum,0,sizeof(sum));
}
 
int main(){
    cl();
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&sum[i]);
        sum[i]+=sum[i-1];
    }
    for(int i=1;i<=n;i++){
        dp[i][1]=1;
        int k=i,res=-1;
        for(int j=i+1;j<=n;j++){
            while(k&&sum[i]-sum[k-1]<=sum[j]-sum[i]) res=max(res,dp[i][k--]);
            if(res==-1) dp[j][i+1]=-1;
            else dp[j][i+1]=max(dp[j][i+1],res+1);
            //printf("i=%d j=%d k=%d
",i,j,k); 
        }
    }
    for(int i=1;i<=n;i++) ans=max(ans,dp[n][i]);
    if(ans==-1) printf("-1");
    else printf("%d",n-ans);
}
原文地址:https://www.cnblogs.com/renjianshige/p/7192505.html