http://uoj.ac/problem/125 (题目链接)

题意

  在网格上写“NOI”,每个格子上有一些权值,要求覆盖的权值最大。书写有一些规则。

Solution

  将“NOI”分成11个部分,每个部分都是有几个有相同特点的矩形构成的,按列dp前缀最大值优化一下即可。看起来很难码的样子,其实套路都差不多,但是想清楚,一些细节处理到位,平时习惯好一点就可以很快写完辣。

  ${f[p][i][j][k]}$表示第${p}$个部分,正在dp第${i}$列,矩形上边界为${j}$,下边界为${k}$时,最大权值。

  ${mx[p][i][j][k]}$表示的是第${p}$个部分,第${i}$列,与上边界${j}$,下边界${k}$相关的前缀最大值。

  其实比较恶心的就是第二部分,你需要处理出这样的一个前缀最大值:上边界的区间在${[1,j]}$,下边界的区间在${[j+1,k]}$。这个并不好直接求出来,所以我们把它分成两部分:上边界区间在${[1,j]}$,下边界固定在${j+1}$;以及上边界在${[1,j]}$,下边界在${[j,k]}$。这样就非常好处理了。

  第${i}$列那一维再滚动一下就好了。

细节

  初始化什么的。然后${j,k}$按照它们的意义${for}$过去可能会清晰一些吧。

代码

// uoj125
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
#define LL long long
#define inf (1ll<<30)
#define MOD 1000000007
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std; const int maxn=160,maxm=510;
int a[maxn][maxm],s[maxm][maxn],up[maxn];
int f[12][maxn][maxn],g[12][maxn][maxn],mx[12][maxn][maxn];
int n,m; int main() {
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++) scanf("%d",&a[i][j]);
for (int j=1;j<=m;j++)
for (int i=1;i<=n;i++) s[j][i]=s[j][i-1]+a[i][j];
for (int i=0;i<=11;i++)
for (int j=0;j<=n+1;j++)
for (int k=0;k<=n+1;k++) f[i][j][k]=g[i][j][k]=mx[i][j][k]=-inf;
for (int i=0;i<=n+1;i++) up[i]=-inf;
int ans=-inf;
for (int i=1;i<=m;i++) {
//第1部分
for (int j=1;j<=n;j++)
for (int k=j;k<=n;k++)
f[1][j][k]=max(g[1][j][k],0)+s[i][k]-s[i][j-1];
//第2部分
for (int j=1;j<=n;j++)
for (int k=n;k>=j;k--) mx[1][j][k]=max(g[1][j][k],mx[1][j][k+1]);
for (int k=1;k<=n;k++) {
up[k]=-inf;
for (int j=1;j<=k;j++) up[k]=max(up[k],g[2][j][k]);
}
for (int k=1;k<=n;k++)
for (int j=1;j<=k;j++) mx[2][j][k]=max(mx[2][j-1][k],g[2][j][k]);
for (int j=1;j<=n;j++)
for (int k=j;k<=n;k++) mx[2][j][k]=max(mx[2][j][k-1],mx[2][j][k]);
for (int j=1;j<=n;j++)
for (int k=j;k<=n;k++)
f[2][j][k]=max(up[j-1],max(mx[1][j][k+1],mx[2][j][k]))+s[i][k]-s[i][j-1];
//第3部分
for (int k=1;k<=n;k++)
for (int j=k;j>=1;j--) mx[2][j][k]=max(mx[2][j+1][k],g[2][j][k]);
for (int j=1;j<=n;j++)
for (int k=j;k<=n;k++)
f[3][j][k]=max(g[3][j][k],mx[2][j+1][k])+s[i][k]-s[i][j-1];
//第4部分
f[4][0][0]=g[4][0][0];
for (int j=1;j<=n;j++)
for (int k=j;k<=n;k++) f[4][0][0]=max(f[4][0][0],g[3][j][k]);
//第5部分
for (int j=1;j<=n;j++)
for (int k=j+2;k<=n;k++) f[5][j][k]=g[4][0][0]+s[i][k]-s[i][j-1];
//第6部分
for (int j=1;j<=n;j++)
for (int k=j+2;k<=n;k++) f[6][j][k]=max(g[5][j][k],g[6][j][k])+s[i][j]-s[i][j-1]+s[i][k]-s[i][k-1];
//第7部分
for (int j=1;j<=n;j++)
for (int k=j+2;k<=n;k++) f[7][j][k]=g[6][j][k]+s[i][k]-s[i][j-1];
//第8部分
f[8][0][0]=g[8][0][0];
for (int j=1;j<=n;j++)
for (int k=j+2;k<=n;k++) f[8][0][0]=max(f[8][0][0],g[7][j][k]);
//第9部分
for (int j=1;j<=n;j++)
for (int k=j+2;k<=n;k++) f[9][j][k]=max(g[9][j][k],g[8][0][0])+s[i][j]-s[i][j-1]+s[i][k]-s[i][k-1];
//第10部分
for (int j=1;j<=n;j++)
for (int k=j+2;k<=n;k++) f[10][j][k]=max(g[10][j][k],g[9][j][k])+s[i][k]-s[i][j-1];
//第11部分
for (int j=1;j<=n;j++)
for (int k=j+2;k<=n;k++) {
f[11][j][k]=max(g[10][j][k],g[11][j][k])+s[i][j]-s[i][j-1]+s[i][k]-s[i][k-1];
ans=max(ans,f[11][j][k]);
}
//滚动
for (int j=1;j<=11;j++)
for (int k=0;k<=n;k++)
for (int l=0;l<=n;l++) g[j][k][l]=f[j][k][l];
}
printf("%d\n",ans);
return 0;
}

【uoj125】 NOI2013—书法家的更多相关文章

  1. BZOJ3241/UOJ125 [Noi2013]书法家

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

  2. [Noi2013]书法家

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

  3. BZOJ 3241: [Noi2013]书法家

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

  4. P1398 [NOI2013]书法家

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

  5. luogu P1398 [NOI2013]书法家

    传送门 注意到\(N\ O\ I\)三个字母都可以从左到右拆成三部分,即\(N=\)一个矩形+一堆矩形+一个矩形,\(O=\)一条+两条横的+一条,\(I=\)两条横的+一个矩形+两条横的,所以可以拆 ...

  6. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  7. NOI2013 Day2

    NOI2013 Day2 矩阵游戏 题目描述:设矩阵\(F\) 求\(F[n][m](mod (10^9+7))\) solution: 这题可以求通项解决. 设\(X_i=F[i][m]\), \( ...

  8. bzoj 3242: [Noi2013]快餐店 章鱼图

    3242: [Noi2013]快餐店 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 266  Solved: 140[Submit][Status] ...

  9. bzoj 3240: [Noi2013]矩阵游戏 矩阵乘法+十进制快速幂+常数优化

    3240: [Noi2013]矩阵游戏 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 613  Solved: 256[Submit][Status] ...

随机推荐

  1. 九九乘法表的python复习

    九九开始的复习 这周复习之前的学的知识关于range函数,gormat函数,print的使用总结一下 从一个小例子开始,开始我的回顾吧, 大家都是从那个九九乘法表开始的数学之旅,从一一得一,开始了我们 ...

  2. CHAPTER 8 Out of Darkness 第8章 走出黑暗

    CHAPTER 8 Out of Darkness 第8章 走出黑暗 We expect scientists to be trying to discover new things, and for ...

  3. 高可用OpenStack(Queen版)集群-13.分布式存储Ceph

    参考文档: Install-guide:https://docs.openstack.org/install-guide/ OpenStack High Availability Guide:http ...

  4. mkdir命令详情

    基础命令学习目录首页 原文链接:https://blog.csdn.net/zwlove5280/article/details/74618041 mkdir 是创建目录的命令. 创建一级目录 mkd ...

  5. oraclejdbc

    https://segmentfault.com/q/1010000004952621/a-1020000004955600

  6. spring中的@component

    @component (把普通pojo实例化到spring容器中,相当于配置文件中的 <bean id="" class=""/>) 泛指各种组件, ...

  7. 做一名合格的程序员(learning of a previous team)

    合格程序员的基本素质 作一个真正合格的程序员,或者说就是可以真正合格完成一些代码工作的程序员,应该具 有的素质.  1 团队精神和协作能力 把它作为基本素质,并不是不重要,恰恰相反,这是程序员应该具备 ...

  8. 结对编程-->总结报告

    项目github地址 PSP时间表格 结对编程中关于Information Hiding, Interface Design, Loose Coupling原则的使用 Information Hidi ...

  9. Task 6.2冲刺会议四 /2015-5-17

    今天主要是学习并熟悉了C#的开发流程,把他的文件的大体结构和每个组件之间的联系弄清楚之后.开始写服务器部分的内容.学习过程中,感觉网上的资料有些太鱼龙混杂了,不知道该怎么取舍.明天准备完善服务器的功能 ...

  10. mvc拦截请求IHttpModule

    代码: using System; using System.Collections.Generic; using System.Linq; using System.Web; using Syste ...