CF392E Deleting Substrings(区间dp)

题意就是说给你一个序列a,你每次可以选择一段“山峰形”子串删掉,获得v[长度]的价值,价值可能为负。可以不全删掉,求最大价值。
f[i][j] 把i~j都删掉的最大价值
g[i][j] 把i~j删成a[i],a[i]+1,…,a[j]的形式的最大价值
h[i][j] 把i~j删成a[i],a[i]-1,…,a[j]的形式的最大价值
dp[i] 前i个的最大价值

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 410
inline char gc(){
    static char buf[1<<16],*S,*T;
    if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int n,a[N],w[N],f[N][N],g[N][N],h[N][N],dp[N];
//f[i][j] 把i~j都删掉的最大价值
//g[i][j] 把i~j删成a[i],a[i]+1,...,a[j]的形式的最大价值
//h[i][j] 把i~j删成a[i],a[i]-1,...,a[j]的形式的最大价值
//dp[i] 前i个的最大价值 
inline void Max(int &x,int y){if(y>x) x=y;}
int main(){
//  freopen("a.in","r",stdin);
    n=read();for(int i=0;i<=n;++i) dp[i]=-inf;
    for(int i=0;i<=n;++i)
        for(int j=0;j<=n;++j) f[i][j]=g[i][j]=h[i][j]=-inf;
    for(int i=1;i<=n;++i) w[i]=read();
    for(int i=1;i<=n;++i) a[i]=read();
    for(int i=1;i<=n;++i) f[i][i]=w[1],g[i][i]=h[i][i]=0;
    for(int l=2;l<=n;++l)
        for(int i=1;i<=n;++i){
            int j=i+l-1;if(j>n) break;
            for(int k=i+1;k<=j;++k){
                if(a[k]==a[i]+1&&g[k][j]!=-inf) Max(g[i][j],(i+1>k-1?0:f[i+1][k-1])+g[k][j]);
                if(a[k]==a[i]-1&&h[k][j]!=-inf) Max(h[i][j],(i+1>k-1?0:f[i+1][k-1])+h[k][j]);
                Max(f[i][j],f[i][k-1]+f[k][j]);
            }for(int k=i;k<=j;++k)
                if(g[i][k]!=-inf&&h[k][j]!=-inf) Max(f[i][j],g[i][k]+h[k][j]+w[2*a[k]-a[i]-a[j]+1]);
        }
    dp[0]=0;
    for(int i=1;i<=n;++i){
        dp[i]=dp[i-1];
        for(int j=1;j<=i;++j) Max(dp[i],dp[j-1]+f[j][i]);
    }printf("%d\n",dp[n]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/icefox_zhx/article/details/80819993