zoukankan      html  css  js  c++  java
  • NOI2013 书法家

    题意:

    有一个$n*m$的矩阵.现在要在矩阵中写三个字母"N","O","I",求出写下合法字母的格子的权值和的最大值.

    书写规则如下:

    $n<=150,m<=500,-200<=A[i][j]<=200$

    题解:

    此题的$n,m$范围较小,可以考虑DP.

    分段考虑.

    字母"O"和"I"都可以用简单的前缀和优化在$O(n^{2}*m)$内解决.

    现在考虑"N",把N分为三部分,两边的"一竖"和中间递减的一段.

    每一段都可以用前缀和进行优化.

    思路很简单,就是操作很复杂.

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    const int N=155,M=505,oo=1e9;
    int w[N][M],n,m,DPn[M],DPo[M],DPi[M];
    int dp[N][N][M],f[N][N][M],sum[N][N][M],s[N][N][M],lft[N][N][M],val[N][N][M];///可以开9~10个 
    inline void Max(int &x,int y){if(x<y)x=y;}
    void solveN(){
        int i,j,k,b,t,B,T;
        for(i=1;i<=m;i++){
            for(b=1;b<=n;b++)
                for(t=b;t<=n;t++)sum[b][t][i]=sum[b][t-1][i]+w[t][i];
            DPn[i]=-oo;
        }
        for(b=1;b<=n;b++){
            for(t=b;t<=n;t++){
                for(i=1;i<=m;i++){
                    s[b][t][i]=s[b][t][i-1]+sum[b][t][i];//第i列[b,t]
                    lft[b][t][i]=sum[b][t][i]+max(0,lft[b][t][i-1]);
                }
            }
        }
        //得到第二列的dp值 
        for(i=0;i<=n;i++)
            for(j=0;j<=n;j++)    
                for(k=0;k<=m;k++)dp[i][j][k]=-oo;
        for(B=1;B<=n;B++){
            for(i=1;i<=m;i++)f[B][n][i]=-oo;
            for(T=n-1;T>=B;T--){//第二行最后一个不可能是n 对! 
                int mx=-oo;
                for(i=1;i<=m;i++){
                    dp[B][T][i]=mx+s[B][T][i];//Max{s[B][T][i]-s[B][T][j]+f[B][T][j]}//j<i求出前缀f-s的最值 
                    f[B][T][i]=max(f[B][T+1][i],lft[B][T+1][i]);  
                    Max(mx,f[B][T][i]-s[B][T][i]);//注意f还没求呢 
                }
            } 
        }
        for(i=0;i<=n;i++)
            for(j=0;j<=n;j++)
                for(k=0;k<=m;k++)f[i][j][k]=val[i][j][k]=-oo;
        for(B=1;B<=n;B++){
            for(i=2;i<=m;i++)
                f[B][B-1][i]=val[B-1][B-1][i];
            for(T=B;T<=n;T++){
                int mx=-oo;
                for(i=2;i<=m;i++){//从第三列开始的dp值 
                    Max(dp[B][T][i],mx+s[B][T][i]);//dp[B][T][i]=s[B][T][i]+Max{f[B][T][j]-s[B][T][j]}.j<i
                    val[B][T][i]=max(val[B-1][T][i],dp[B][T][i]);
                    f[B][T][i]=max(f[B][T-1][i],val[B][T][i]);
                    Max(mx,f[B][T][i]-s[B][T][i]);
                    
                }
            }
        } 
        for(i=0;i<=n;i++)
            for(j=0;j<=n;j++)
                for(k=0;k<=m;k++)f[i][j][k]=-oo;
        for(B=n-1;B>=1;B--){ 
            for(T=B+1;T<=n;T++){
                int mx=-oo;
                for(i=1;i<=m;i++){
                    Max(DPn[i],mx+s[B][T][i]);//=s[B][T][i]+Max{f[B][T][j]-}这里用赋值  
                    f[B][T][i]=max(f[B+1][T][i],dp[B+1][T][i]);
                    Max(mx,f[B][T][i]-s[B][T][i]);
                }
            }
        }
        //答案是-5才对 
        for(i=1;i<=m;i++)Max(DPn[i],DPn[i-1]);
    } 
    int ss[N][M];//第i行第前j个 
    void solveO(){
        int i,j,k,B,T;
         for(j=1;j<=m;j++){
             DPo[j]=-oo;
            for(i=1;i<=n;i++)
             ss[i][j]=ss[i][j-1]+w[i][j]; 
        }
        for(B=1;B<=n;B++){//至少是3 
            for(T=B+2;T<=n;T++){
                int mx=-oo;
                for(i=6;i<=m;i++){//至少是6 
                    Max(DPo[i],mx+sum[B+1][T-1][i]+ss[B][i]+ss[T][i]);//j<i-1
                    Max(mx,-ss[B][i-2]-ss[T][i-2]+sum[B+1][T-1][i-1]+DPn[i-3]);
                }
            }
        } 
        for(i=1;i<=m;i++)Max(DPo[i],DPo[i-1]);
    }
    int rght[N][N][M];
    void solveI(){
        int i,j,k,B,T;
        for(j=m;j>=1;j--){
            for(i=1;i<=n;i++){
                for(k=i;k<=n;k++)
                    rght[i][k][j]=w[i][j]+w[k][j]+max(rght[i][k][j+1],0);
            }
            DPi[j]=-oo;
        }
        for(i=1;i<=n;i++){
            for(k=i+2;k<=n;k++){
                lft[i][k][0]=lft[i][k][1]=-oo;
                for(j=2;j<=m;j++){
                    lft[i][k][j]=w[i][j]+w[k][j]+max(lft[i][k][j-1],DPo[j-2]);
                }
            }
        }
        for(B=1;B<=n;B++){
            for(T=B+2;T<=n;T++){
                int mx=-oo;
                for(i=8;i<m;i++){
                    Max(DPi[i],mx+s[B][T][i]+rght[B][T][i+1]);
                    Max(mx,lft[B][T][i]-s[B][T][i]);//ss[B][i]-ss[B][j-1]+ss[T][i]-ss[B][j-1] +DPo[j-2] j<
                }
            }
        }
        for(i=1;i<=m;i++)Max(DPi[i],DPi[i-1]);
    }
    int main(){ 
        scanf("%d %d",&n,&m);
        int i,j,k;
        DPn[0]=DPo[0]=DPi[0]=-oo;
        for(i=1;i<=n;i++){
            for(j=1;j<=m;j++)
                scanf("%d",&w[i][j]);
        }
        solveN();
        solveO();
        solveI();
        printf("%d
    ",DPi[m]);
        return 0;
        
    }
    View Code

    注意:

    调试时,先把思路顺一遍,再去调试.否则十分耗时耗力.

    $By LIN452$

    $2017.06.07$

  • 相关阅读:
    《软件工程》团队第一阶段Sprint检查表
    灭霸第一阶段绩效评估
    【Copy攻城狮日志】docker搭建jenkins拉取svn代码打包vue项目部署到nginx
    前端移动App开发环境搭建
    【Copy攻城狮日志】Node快速重命名文件,告别Potplay字幕困扰问题
    centos部署yapi爬坑记
    mint-ui之picker爬坑记
    前端内网穿透,localtunnel你值得拥有!
    Visual Studio Live Share不完全指北
    jq跑马灯效果
  • 原文地址:https://www.cnblogs.com/Lay-with-me/p/6953034.html
Copyright © 2011-2022 走看看