题意:要在一张网格纸上画出NOI图形,使得所占格子的权值和最大。

解:暴力DP即可...

从左往右,每个字母都可以被划分成三块,且每块都可用上下两维来表示。

于是一块一块的DP。考虑如何O(1)转移。显然只有N的中间那一块不好转移,别的都是直接转移。

N的三块的两个连接处之间,可以枚举必须持平的那个端点,另一个用前缀最值。

N第二块内部,考虑枚举后一个矩形的上边界,逐步扩展下边界。此时发现每扩展一步,可能的决策集合会增加:左边一格,下边界为刚扩展的那一格,上边界在枚举的上边界以上的所有状态。

于是对于每个下边界,预处理出上边界从上到下的一个前缀最值,加到决策集合里取max即可。

 #include <bits/stdc++.h>

 const int INF = 0x3f3f3f3f;

 #define g f[FLAG]
#define h f[FLAG ^ 1] int f[][][][], FLAG, n, m;
int s[][], p[], temp[][]; inline int getSum(int i, int l, int r) {
if(l > r) return ;
return s[r][i] - s[l - ][i];
} inline void out() {
for(int i = ; i <= m; i++) {
for(int up = ; up <= n; up++) {
for(int down = up; down <= n; down++) {
printf("%d ", g[i][up][down]);
}
}
puts("");
}
puts("");
return;
} inline void outp() {
printf("p : ");
for(int i = ; i <= m; i++) {
printf("%d ", p[i]);
}
puts("");
puts("");
return;
} int main() {
//printf("%d \n", sizeof(f) / 1048576); scanf("%d%d", &n, &m);
for(int i = ; i <= n; i++) {
for(int j = ; j <= m; j++) {
scanf("%d", &s[i][j]);
s[i][j] += s[i - ][j];
}
} FLAG = ; /// N 1
memset(g, ~0x3f, sizeof(g));
for(int i = ; i <= m; i++) {
for(int up = ; up < n; up++) {
for(int down = up + ; down <= n; down++) {
g[i][up][down] = std::max(, g[i - ][up][down]) + getSum(i, up, down);
}
}
} //out(); FLAG ^= ; /// N 1.5
memset(g, ~0x3f, sizeof(g));
for(int i = ; i <= m; i++) {
for(int up = ; up < n; up++) {
int large = -INF;
for(int down = n - ; down >= up; down--) {
large = std::max(large, h[i - ][up][down + ]);
g[i][up][down] = large + getSum(i, up, down);
}
}
} //out(); FLAG ^= ; /// N 2
//memset(g, ~0x3f, sizeof(g));
memcpy(g, h, sizeof(h));
for(int i = ; i <= m; i++) {
memset(temp, ~0x3f, sizeof(temp));
for(int down = ; down <= n; down++) {
for(int up = ; up <= down; up++) {
temp[down][up] = std::max(temp[down][up - ], std::max(g[i - ][up][down], h[i - ][up][down]));
}
}
for(int up = ; up <= n; up++) {
int large = temp[up - ][up - ];
for(int down = up; down <= n; down++) {
large = std::max(large, temp[down][up]);
g[i][up][down] = std::max(large + getSum(i, up, down), h[i][up][down]);
}
}
} //out(); FLAG ^= ; /// N 2.5
memset(g, ~0x3f, sizeof(g));
for(int i = ; i <= m; i++) {
for(int down = ; down <= n; down++) {
int large = -INF;
for(int up = down - ; up >= ; up--) {
large = std::max(large, h[i - ][up + ][down]);
g[i][up][down] = large + getSum(i, up, down);
}
}
} //out(); FLAG ^= ; /// N 3
memset(g, ~0x3f, sizeof(g));
for(int i = ; i <= m; i++) {
for(int up = ; up < n; up++) {
for(int down = up + ; down <= n; down++) {
g[i][up][down] = std::max(h[i][up][down], g[i - ][up][down] + getSum(i, up, down));
}
}
} //out(); /// get p : max of g
memset(p, ~0x3f, sizeof(p));
for(int i = ; i <= m; i++) {
p[i] = p[i - ];
for(int up = ; up <= n; up++) {
for(int down = ; down <= n; down++) {
p[i] = std::max(p[i], g[i][up][down]);
}
}
} //outp(); //out(); //printf(" O 1 \n"); FLAG ^= ; /// O 1
memset(g, ~0x3f, sizeof(g));
for(int i = ; i <= m; i++) {
for(int up = ; up < n - ; up++) {
for(int down = up + ; down <= n; down++) {
g[i][up][down] = p[i - ] + getSum(i, up, down);
}
}
} //out(); //printf(" O 2 \n"); FLAG ^= ; /// O 2
memset(g, ~0x3f, sizeof(g));
for(int i = ; i <= m; i++) {
for(int up = ; up < n - ; up++) {
for(int down = up + ; down <= n; down++) {
g[i][up][down] = std::max(h[i - ][up][down], g[i - ][up][down]) + getSum(i, up, up) + getSum(i, down, down);
}
}
} //out(); FLAG ^= ; /// O 3
memset(g, ~0x3f, sizeof(g));
for(int i = ; i <= m; i++) {
for(int up = ; up < n - ; up++) {
for(int down = up + ; down <= n; down++) {
g[i][up][down] = h[i - ][up][down] + getSum(i, up, down);
}
}
} //out(); /// get p : max of g
memset(p, ~0x3f, sizeof(p));
for(int i = ; i <= m; i++) {
p[i] = p[i - ];
for(int up = ; up < n - ; up++) {
for(int down = up + ; down <= n; down++) {
p[i] = std::max(p[i], g[i][up][down]);
}
}
} //outp(); //out(); FLAG ^= ; /// I 1
memset(g, ~0x3f, sizeof(g));
for(int i = ; i <= m; i++) {
for(int up = ; up < n - ; up++) {
for(int down = up + ; down <= n; down++) {
g[i][up][down] = std::max(p[i - ], g[i - ][up][down]) + getSum(i, up, up) + getSum(i, down, down);
}
}
} //out(); FLAG ^= ; /// I 2
memset(g, ~0x3f, sizeof(g));
for(int i = ; i <= m; i++) {
for(int up = ; up < n - ; up++) {
for(int down = up + ; down <= n; down++) {
g[i][up][down] = std::max(g[i - ][up][down], h[i - ][up][down]) + getSum(i, up, down);
}
}
} //out();
int ans = -INF; FLAG ^= ; /// I 3
memset(g, ~0x3f, sizeof(g));
for(int i = ; i <= m; i++) {
for(int up = ; up < n - ; up++) {
for(int down = up + ; down <= n; down++) {
g[i][up][down] = std::max(g[i - ][up][down], h[i - ][up][down]) + getSum(i, up, up) + getSum(i, down, down);
ans = std::max(g[i][up][down], ans);
}
}
} //out(); printf("%d\n", ans);
return ;
}

AC代码

LOJ#2668 书法家的更多相关文章

  1. BZOJ 2668 交换棋子(费用流)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2668 题意:有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子中的棋子,最终达到目标状 ...

  2. 【BZOJ】【2668】【CQOI2012】交换棋子

    网络流/费用流 跪跪跪,居然还可以这样建图…… 题解:http://www.cnblogs.com/zig-zag/archive/2013/04/21/3033485.html 考虑每个点的交换限制 ...

  3. [Noi2016]区间 BZOJ4653 洛谷P1712 Loj#2086

    额... 首先,看到这道题,第一想法就是二分答案+线段树... 兴高采烈的认为我一定能AC,之后发现n是500000... nlog^2=80%,亲测可过... 由于答案是求满足题意的最大长度-最小长 ...

  4. Loj #2192. 「SHOI2014」概率充电器

    Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...

  5. Loj #3096. 「SNOI2019」数论

    Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...

  6. Loj #3093. 「BJOI2019」光线

    Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ...

  7. Loj #3089. 「BJOI2019」奥术神杖

    Loj #3089. 「BJOI2019」奥术神杖 题目描述 Bezorath 大陆抵抗地灾军团入侵的战争进入了僵持的阶段,世世代代生活在 Bezorath 这片大陆的精灵们开始寻找远古时代诸神遗留的 ...

  8. Loj #2542. 「PKUWC2018」随机游走

    Loj #2542. 「PKUWC2018」随机游走 题目描述 给定一棵 \(n\) 个结点的树,你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(Q\) 次询问,每次 ...

  9. Loj #2331. 「清华集训 2017」某位歌姬的故事

    Loj #2331. 「清华集训 2017」某位歌姬的故事 IA 是一名会唱歌的女孩子. IOI2018 就要来了,IA 决定给参赛选手们写一首歌,以表达美好的祝愿.这首歌一共有 \(n\) 个音符, ...

随机推荐

  1. Spring Boot 自定义 starter

    一.简介 SpringBoot 最强大的功能就是把我们常用的场景抽取成了一个个starter(场景启动器),我们通过引入springboot 为我提供的这些场景启动器,我们再进行少量的配置就能使用相应 ...

  2. linux下mysql区分大小写的内容

    1.数据库名严格区分大小写2.表名严格区分大小写的3.表的别名严格区分大小写4.变量名严格区分大小写5.列名在所有的情况下均忽略大小写6.列的别名在所有的情况下均忽略大小写

  3. idea Maven项目找不到相关依赖包(红色波浪线)

    前两天做项目的时候,把团队其他人的代码从git同步到自己电脑上,出现了冲突.发现是maven依赖出现了问题,之前的截图找不到了,我就简单描述一下.就是下图箭头所示位置出现了红色波浪线. 在网上找了很多 ...

  4. selenium-测试框架搭建(十三)

    思路 分离业务代码和测试数据,提高代码可维护性,实现自动化,减少重复劳动. 一个测试框架大概由配置文件,测试数据,测试用例,相关文件(发送邮件等),测试日志,断言和测试报告等模块组成. 结构 以页面为 ...

  5. mysql基本操作(1)

    1.mysql数据库客户端安装 brew install mysql-client 2.mysql 连接数据库 mysql -h <数据库地址> -P <端口> -u < ...

  6. 内存与IO的交换【转】

    用户进程的内存页分为两种: file-backed pages(文件背景页) anonymous pages(匿名页) 比如进程的代码段.映射的文件都是file-backed,而进程的堆.栈都是不与文 ...

  7. gradle下载及配置

    windows安装 1.下载地址:http://services.gradle.org/distributions/ 2.下载**-bin.zip,解压即可 配置环境变量:gradle_home:D: ...

  8. SQL insert into select 语句

    遇到权限数据变更的需要批量到别的平台, 在175平台添加一个权限需要, 批量到别的现有平台, 以后的建站, 会把sql放到自动建站里面; 权限的 insert into select 表一: `ous ...

  9. 好程序员web前端分享如何理解JS的单线程

    好程序员web前端分享如何理解JS单线程,JS本质是单线程的.也就是说,它并不能像JAVA语言那样,两个线程并发执行. 但我们平时看到的JS,分明是可以同时运作很多任务的,这又是怎么回事呢? 首先,J ...

  10. [LeetCode] 20. 有效的括号

    题目链接:https://leetcode-cn.com/problems/valid-parentheses/ 题目描述: 给定一个只包括 '(',')','{','}','[',']' 的字符串, ...