zoukankan      html  css  js  c++  java
  • CF392E Deleting Substrings

    Solution

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

    然后发现 (nleq 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{[1leq w_j-w_i+1leq n](g_{i,k}+v_{w_j-w_i+1}),[1leq w_i-w_j+1leq 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}{[1leq 2w_k-w_i-w_j+1leq 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
    ",dp[n]);
        return 0;
    }
    
  • 相关阅读:
    杜教筛刷题总结
    后缀自动机刷题总结
    回文自动机刷题总结
    后缀数组刷题总结
    LCT刷题总结
    省选模拟一题解
    FFT/NTT中档题总结
    二项式反演总结
    JS只能输入数字,数字和字母等的正则表达式
    jquery 条件搜索某个标签下的子标签
  • 原文地址:https://www.cnblogs.com/jasony/p/13734899.html
Copyright © 2011-2022 走看看