• luogu P1437 [HNOI2004]尻♂砖块


    传送门

    想明白了其实不难 强行瞎扯

    这题的限制比较烦,导致了一行行转移几乎不能做(吧)

    那么一列列转移呢?

    (f_{i,j,k})表示前(i)列,取(j)个,其中第(i)列取从上往下前(k)个的答案

    因为要取到一个砖块,要把该砖块上方以及右上方的先取走,那么如果这一列取(k)个,下一列最少取(k-1)个;反过来,对于列(i),上一列的(k)的取值范围为([1,k+1]),是个前缀,可以前缀最大值优化

    写个方程就没了

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    #define LL long long
    #define il inline
    #define re register
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    #define inf 999999999
    
    using namespace std;
    const int N=50+10;
    il LL rd()
    {
        re LL x=0,w=1;re char ch=0;
        while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
        return x*w;
    }
    int n,m,a[N][N],f[N][N*N][N];   //dp用的数组同时用来记录前缀k最大值(懒)
    
    int main()
    {
      n=rd(),m=rd();
      for(int i=1;i<=n;i++)
        for(int j=1;j<=n-i+1;j++)
          a[i][j]=a[i-1][j]+rd();   //前缀和存储
      for(int i=1,t=n;i<=n;i++,t+=n-i+1,t=min(t,m))
        for(int j=1;j<=t;j++)
          {
            f[i][j][0]=max(f[i-1][j][0],f[i-1][j][1]);
            for(int k=1;k<=n-i+1;k++)
              {
                if(j-k>=0) f[i][j][k]=max(f[i][j][k],f[i-1][j-k][k+1]+a[k][i]);
              }
            for(int k=1;k<=n-i+1;k++) f[i][j][k]=max(f[i][j][k],f[i][j][k-1]);
          }
      printf("%d
    ",max(f[n][m][0],f[n][m][1]));
      return 0;
    }
    
    
    
  • 相关阅读:
    ASP.NET 构建高性能网站 架构设计
    ASP.NET 构建高性能网站 架构设计
    Vim和Vi的常用命令
    Vim和Vi的常用命令
    Vim和Vi的常用命令
    【收藏】前端知识体系完整版本
    【收藏】前端知识体系完整版本
    Ubuntu-升级linux软件源,安装vim/五笔
    高阶函数---swift中的泛型介绍(一步步实现Map函数)
    Go基础学习(二)
  • 原文地址:https://www.cnblogs.com/smyjr/p/9682162.html
Copyright © 2020-2023  润新知