CF392E Deleting Substrings

Solution

首先,题的意思是删连续上升的/连续下降的/先上升后的。

然后发现 \(n\leq 400\) ,所以可以考虑区间DP

\(f_{i,j}\) 为删完 \(w_i,\cdots, w_j\) 的最大分数, \(g_{i,j}\) 为将 \(w_i,\cdots,w_j\) 删成以 \(w_i\) 开头, \(w_j\) 结尾的连续上升的最大分数, \(h_{i,j}\) 为将 \(w_i,\cdots,w_j\) 删成以 \(w_i\) 开头, \(w_j\) 结尾的连续下降的最大分数。

可以列出状态转移方程:

\[g_{i,j}=\max\{[w_{j-1}+1=w_j]g_{i,j-1},\max_{k=i}^{j-2}\{[w_k+1=w_j](g_{i,k}+f_{k+1,j-1})\}\} \]

意思是可以直接填 \(w_j\) ,也可以删除 \(w_{k+1},\cdots,w_{j-1}\) ,然后填 \(w_j\)

\[h_{i,j}=\max\{[w_{j-1}-1=w_j]h_{i,j-1},\max_{k=i}^{j-2}\{[w_k-1=w_j](h_{i,k}+f_{k+1,j-1})\}\} \]

和上面那个同理。

\[f_{i,j}=\max\{[1\leq w_j-w_i+1\leq n](g_{i,k}+v_{w_j-w_i+1}),[1\leq w_i-w_j+1\leq n](h_{i,k}+v_{w_i-w_j+1}),\\\max_{k=i}^{j-1}\{f_{i,k}+f_{k+1,j}\},\max_{k=i+1}^{j-1}\{[1\leq 2w_k-w_i-w_j+1\leq n]g_{i,k}+h_{k,j}+v_{2w_k-w_i-w_j+1}\}\} \]

最外层 \(\max\) 中,第一个是删成连续上升的,第二个是删成连续下降的,第三个是先删 \(w_i,\cdots,w_k\)\(f_{i,k}\) 再删 \(w_k,\cdots,w_j\)\(f_{k,j}\) ,第四个是删成先上升再下降的。

\[dp_i=\max_{j=0}^{j<i}\{dp_{i-1},dp_j+f_{j+1,i}\} \]

这是最显然的,就不解释了。

注意:要记得把 \(f_{i,i}\) 初始化为 \(1\)\(g_{i,i},h_{i,i}\) 初始化为 \(0\)

代码

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;
const int N=410,INF=1e9;
int n;
int v[N],w[N],f[N][N],g[N][N],h[N][N],dp[N];

inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
    return x*f;
}

inline void Max(int &a,int b){
    if(a<b) a=b;
}

int main(){
    n=read();
    for(int i=1;i<=n;i++) v[i]=read();
    for(int i=1;i<=n;i++) w[i]=read();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            f[i][j]=g[i][j]=h[i][j]=-INF;
    for(int i=n;i>0;i--){
        f[i][i]=v[1];
        g[i][i]=h[i][i]=0;
        for(int j=i+1;j<=n;j++){
            for(int k=i;k<j-1;k++)
                if(w[k]+1==w[j]) Max(g[i][j],g[i][k]+f[k+1][j-1]);
            if(w[j-1]+1==w[j]) Max(g[i][j],g[i][j-1]);
        }
        for(int j=i+1;j<=n;j++){
            for(int k=i;k<j-1;k++)
                if(w[k]-1==w[j]) Max(h[i][j],h[i][k]+f[k+1][j-1]);
            if(w[j-1]-1==w[j]) Max(h[i][j],h[i][j-1]);
        }
        for(int j=i;j<=n;j++){
            if(w[j]-w[i]+1>0&&w[j]-w[i]+1<=n) Max(f[i][j],g[i][j]+v[w[j]-w[i]+1]);
            if(w[i]-w[j]+1>0&&w[i]-w[j]+1<=n) Max(f[i][j],h[i][j]+v[w[i]-w[j]+1]);
            for(int k=i;k<j;k++) Max(f[i][j],f[i][k]+f[k+1][j]);
            for(int k=i+1;k<j;k++)
                if(2*w[k]-w[i]-w[j]+1>0&&2*w[k]-w[i]-w[j]+1<=n)
                    Max(f[i][j],g[i][k]+h[k][j]+v[2*w[k]-w[j]-w[i]+1]);
        }
    }
    for(int i=1;i<=n;i++){
        dp[i]=dp[i-1];
        for(int j=0;j<i;j++) Max(dp[i],dp[j]+f[j+1][i]);
    }
    printf("%d\n",dp[n]);
    return 0;
}
posted @ 2020-09-26 14:22  jasony_sam  阅读(156)  评论(0编辑  收藏  举报