传送门

注意到\(N\ O\ I\)三个字母都可以从左到右拆成三部分,即\(N=\)一个矩形+一堆矩形+一个矩形,\(O=\)一条+两条横的+一条,\(I=\)两条横的+一个矩形+两条横的,所以可以拆成\(13\)个部分转移(\(9\)个字母部分,\(4\)个空白部分)

设\(f_{i,j,l,r}\)表示第\(i\)列,放的是字母的\(j\)部分,放了从\(l\)行到\(r\)行的最大值,\(g_{i,j}\)表示第\(i\)列,放的是的空白\(j\)部分的最大值.转移根据不同的部分,枚举下一列怎么放,但是这样复杂度不对.可以发现只有空白部分转移到字母部分和\(N\)部分转移需要枚举放哪里,其他的可以直接继承上一个状态的\(l,r\)

空白部分转移比较简单,这里主要看\(N\).首先从第一部分转移到第二部分,如果放了\(l,r\),那么前一个状态的后面两维为\(l,r'(r'>r)\),所以可以记后缀最大值直接转移.然后是第二部分之间的转移,上一个状态后两维是\(l',r'(l'\ge l,l-1\le r'\le r)\),这个也可以前缀最值优化.从第二部分转移到第三部分,前一个状态的后面两维为\(l',r(l'<l)\),可以前缀最值优化

具体细节详见代码

#include<bits/stdc++.h>
#define LL long long
#define uLL unsigned long long
#define il inline using namespace std;
const int N=150+10,M=500+10;
il int rd()
{
int x=0,w=1;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][M],s[N][M],f[2][10][N][N],g[2][4],ss[N]; int main()
{
n=rd(),m=rd();
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
a[i][j]=rd(),s[i][j]=s[i-1][j]+a[i][j];
memset(f,-0x3f,sizeof(f)),memset(g,-0x3f,sizeof(g));
int nw=1,la=0;
g[la][0]=0;
for(int j=1;j<=m+1;++j)
{
memcpy(g[nw],g[la],sizeof(g[la]));
//
for(int l=1;l<=n;++l)
for(int r=l+1;r<=n;++r)
f[nw][1][l][r]=max(g[la][0],f[la][1][l][r])+s[r][j]-s[l-1][j];
for(int l=1;l<=n;++l)
for(int r=n,mx=-(1<<29);r>=l;--r)
{
f[nw][2][l][r]=max(f[nw][2][l][r],mx+s[r][j]-s[l-1][j]);
mx=max(mx,f[la][1][l][r]);
}
memset(ss,-0x3f,sizeof(ss));
for(int l=1;l<=n;++l)
for(int r=l,mx=ss[l-1];r<=n;++r)
{
ss[r]=max(ss[r],f[la][2][l][r]);
mx=max(mx,ss[r]);
f[nw][2][l][r]=max(f[nw][2][l][r],mx+s[r][j]-s[l-1][j]);
}
for(int r=n;r;--r)
for(int l=r,mx=-(1<<29);l;--l)
{
f[nw][3][l][r]=max(f[nw][3][l][r],mx+s[r][j]-s[l-1][j]);
mx=max(mx,f[la][2][l][r]);
}
for(int l=1;l<=n;++l)
for(int r=l+1;r<=n;++r)
{
f[nw][3][l][r]=max(f[nw][3][l][r],f[la][3][l][r]+s[r][j]-s[l-1][j]);
g[nw][1]=max(g[nw][1],f[la][3][l][r]);
}
//
for(int l=1;l<=n;++l)
for(int r=l+2;r<=n;++r)
f[nw][4][l][r]=g[la][1]+s[r][j]-s[l-1][j];
for(int l=1;l<=n;++l)
for(int r=l+2;r<=n;++r)
f[nw][5][l][r]=max(f[la][4][l][r],f[la][5][l][r])+a[l][j]+a[r][j];
for(int l=1;l<=n;++l)
for(int r=l+2;r<=n;++r)
{
f[nw][6][l][r]=f[la][5][l][r]+s[r][j]-s[l-1][j];
g[nw][2]=max(g[nw][2],f[la][6][l][r]);
}
//
for(int l=1;l<=n;++l)
for(int r=l+2;r<=n;++r)
f[nw][7][l][r]=max(g[la][2],f[la][7][l][r])+a[l][j]+a[r][j];
for(int l=1;l<=n;++l)
for(int r=l+2;r<=n;++r)
f[nw][8][l][r]=max(f[la][7][l][r],f[la][8][l][r])+s[r][j]-s[l-1][j];
for(int l=1;l<=n;++l)
for(int r=l+2;r<=n;++r)
{
f[nw][9][l][r]=max(f[la][8][l][r],f[la][9][l][r])+a[l][j]+a[r][j];
g[nw][3]=max(g[nw][3],f[la][9][l][r]);
}
//
memset(f[la],-0x3f,sizeof(f[la])),memset(g[la],-0x3f,sizeof(g[la]));
nw^=1,la^=1;
}
printf("%d\n",g[la][3]);
return 0;
}

luogu P1398 [NOI2013]书法家的更多相关文章

  1. P1398 [NOI2013]书法家

    传送门 就是个普及组 $dp$ 合集,把 $NOI$ 从左到右拆成 $9$ 个部分,每个部分都可以分别 $dp$ 除了 $N$ 的中间部分比较恶心以外其他都还好,自己推一下然后就知道转移,就 $N$ ...

  2. [Noi2013]书法家

    来自FallDream的博客,未经允许,请勿转载,谢谢. 小E同学非常喜欢书法,他听说NOI2013已经开始了,想题一幅“NOI”的字送给大家. 小E有一张非常神奇的纸,纸可以用一个n 行m 列的二维 ...

  3. BZOJ3241/UOJ125 [Noi2013]书法家

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  4. BZOJ 3241: [Noi2013]书法家

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3241 题意: 思路:把每个字母分成三部分,两个字母之间还有空的列,所以我一共设了11个状态 ...

  5. 【uoj125】 NOI2013—书法家

    http://uoj.ac/problem/125 (题目链接) 题意 在网格上写“NOI”,每个格子上有一些权值,要求覆盖的权值最大.书写有一些规则. Solution 将“NOI”分成11个部分, ...

  6. luogu P1399 [NOI2013]快餐店

    传送门 注意到答案为这个基环树直径\(/2\) 因为是基环树,所以考虑把环拎出来.如果直径不过环上的边,那么可以在环上每个点下挂的子树内\(dfs\)求得.然后如果过环上的边,那么环上的部分也是一条链 ...

  7. luogu P1397 [NOI2013]矩阵游戏

    传送门 题目中那两个递推式显然可以写成矩乘的形式,然后十进制快速幂即可.这里不再赘述 只有两个递推式,我们可以考虑一波推式子,首先第一行的元素应该分别是\(1,a+b,a^2+ab+b,a^3+a^2 ...

  8. luogu P1232 [NOI2013]树的计数

    传送门 这题妙蛙 首先考虑构造出一个合法的树.先重新编号,把bfs序整成\(1,2,3...n\),然后bfs序就是按照从上到下从左往右的遍历顺序,所以可以考虑对bfs序分层,可以知道分层方式只会对应 ...

  9. luogu P1224 [NOI2013]向量内积

    传送门 挺有意思的一道题 暴力60就是枚举每个向量暴力check,随机选向量就能多骗一些分 然后两个向量内积要模\(k\)为\(0\),那么如果全部不为\(0\)就不合法.先考虑\(k=2\),对于向 ...

随机推荐

  1. #381 Div2 Problem C Alyona and mex (思维 && 构造)

    题意 : 题目的要求是构造出一个长度为 n 的数列, 构造条件是在接下来给出的 m 个子区间中, 要求每一个子区间的mex值最大, 然后在这 m 个子区间产生的mex值中取最小的输出, 并且输出构造出 ...

  2. R 去掉非零元素

    X <- X[X!=] Malign_score <- Malign_score[Malign_score>=0.0008]

  3. (48)LINUX应用编程和网络编程之三Linux获取系统信息

    3.3.1.关于时间的概念 3.3.1.1.GMT时间 (1)GMT是格林尼治时间,也就是格林尼治地区的当地之间. (2)GMT时间的意义?[用格林尼治的当地时间作为全球国际时间],用以描述全球性的事 ...

  4. python学习之路(22)

    使用模块 Python本身就内置了很多非常有用的模块,只要安装完毕,这些模块就可以立刻使用. 我们以内建的sys模块为例,编写一个hello的模块: #!/usr/bin/env python # - ...

  5. 阿里菜鸟知识储备之二——git工具学习

    具体的可以参见这篇博客: http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000 1,什么 ...

  6. Visual Studio 2019 企业版 注册码 百度云下载

    微软官网下载地址:https://visualstudio.microsoft.com/zh-hans/downloads/ Key: Visual Studio 2019 Enterprise 企业 ...

  7. open jdk卸载

    //查找:open jdk # rpm -qa | grep java //卸载open jdk # rpm -e --nodeps 包 # source /etc/profile # java -v ...

  8. leetcode-mid-others-169. Majority Element¶

    mycode  54.93% class Solution(object): def majorityElement(self, nums): """ :type num ...

  9. Flask中的request模板渲染Jinja以及Session

    Flask中的request与django相似介绍几个常用的以后用的时候直接查询即可 1.request from flask import request(用之前先引用,与django稍有不同) r ...

  10. 中国MOOC_零基础学Java语言_第6周 使用对象_1单词长度

    第6周编程题 查看帮助 返回   第6周编程题 依照学术诚信条款,我保证此作业是本人独立完成的. 温馨提示: 1.本次作业属于Online Judge题目,提交后由系统即时判分. 2.学生可以在作业截 ...