「AHOI2014/JSOI2014」拼图
「AHOI2014/JSOI2014」拼图
传送门
看到 \(n \times m \le 10^5\) ,考虑根号分治。
对于 \(n < m\) 的情况,我们可以枚举最终矩形的上下边界 \(tp, bt\),那么我们发现最终矩形一定是由所有满足从第 \(tp\) 行到第 \(bt\) 行都是白格子的矩形顺次连接,并且两端再各自接上一个最大的前缀和一个最大的后缀构成的。
这个我们可以 \(O(m)\) 地算。
总复杂度就是 \(O(n^2m)\),也就是一个根号级别的。
对于 \(n \ge m\) 的情况,我们肯定不能还去枚举上下边界,但是此时我们可以对于每一个白色的格子,都找一个它上面的最远的一个白格子来构成一组上下边界,然后套用第一问的计算方法就好了。
预处理是 \(O(nm)\) 的,总复杂度是 \(O(nm^2)\),还是一个根号级别的。
还有一个坑点就是再找前、后缀矩形时要避免重复使用一个矩阵,所以我们还得记录次大值。
参考代码:
#include <cstdio>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
template < class T > inline T max(T a, T b) { return a > b ? a : b; }
template < class T > inline void read(T& s) {
s = 0; int f = 0; char c = getchar();
while ('0' > c || c > '9') f |= c == '-', c = getchar();
while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
s = f ? -s : s;
}
const int _ = 1e5 + 5;
int s, n, m, l[_], r[_], lr[_], a[_], sum[_], up[_];
struct node { int first, second; } lmx, lmmx, rmx, rmmx;
inline int id(int i, int j) { return i != 0 && j != 0 ? (j - 1) * n + i : 0; }
inline int S(int x1, int y1, int x2, int y2) {
return sum[id(x2, y2)] - sum[id(x2, y1 - 1)] - sum[id(x1 - 1, y2)] + sum[id(x1 - 1, y1 - 1)];
}
inline int calc(int tp, int bt) {
int res = 0;
for (rg int i = 1; i <= s; ++i)
for (rg int ss = 0, j = l[i]; j <= r[i]; ++j) {
if (S(tp, j, bt, j) != 0) ss = 0; else ++ss;
res = max(res, (bt - tp + 1) * ss);
}
int mid = 0;
lmx = lmmx = rmx = rmmx = (node) { 0, 0 };
for (rg int i = 1; i <= s; ++i) {
int ls = 0, rs = 0;
for (rg int j = l[i]; j <= r[i]; ++j) if (S(tp, j, bt, j) != 0) break ; else ++ls;
for (rg int j = r[i]; j >= l[i]; --j) if (S(tp, j, bt, j) != 0) break ; else ++rs;
if (ls == lr[i]) mid += lr[i];
else {
if (ls > lmx.first) lmmx = lmx, lmx = (node) { ls, i };
else if (ls > lmmx.first) lmmx = (node) { ls, i };
if (rs > rmx.first) rmmx = rmx, rmx = (node) { rs, i };
else if (rs > rmmx.first) rmmx = (node) { rs, i };
}
}
if (lmx.second != rmx.second)
res = max(res, (bt - tp + 1) * (lmx.first + mid + rmx.first));
else {
res = max(res, (bt - tp + 1) * (lmmx.first + mid + rmx.first));
res = max(res, (bt - tp + 1) * (rmmx.first + mid + lmx.first));
}
return res;
}
inline void solve() {
read(s), read(n), m = 0;
for (rg int i = 1; i <= s; ++i) {
read(lr[i]), l[i] = m + 1, m += lr[i], r[i] = m;
for (rg int j = 1; j <= n; ++j)
for (rg int k = l[i]; k <= r[i]; ++k) scanf("%1d", a + id(j, k));
}
for (rg int i = 1; i <= n; ++i)
for (rg int j = 1; j <= m; ++j)
sum[id(i, j)] = sum[id(i - 1, j)] + sum[id(i, j - 1)] - sum[id(i - 1, j - 1)] + a[id(i, j)];
int ans = 0;
if (n < m) {
for (rg int i = 1; i <= n; ++i)
for (rg int j = i; j <= n; ++j) ans = max(ans, calc(i, j));
} else {
for (rg int j = 1; j <= m; ++j) {
for (rg int p = 0, i = 1; i <= n; ++i) {
if (a[id(i, j)] != 0) {
for (rg int k = p + 1; k < i; ++k) up[id(k, j)] = p; p = i;
}
for (rg int k = p + 1; k <= n; ++k) up[id(k, j)] = p;
}
}
for (rg int i = 1; i <= n; ++i)
for (rg int j = 1; j <= m; ++j)
if (a[id(i, j)] == 0) ans = max(ans, calc(up[id(i, j)] + 1, i));
}
printf("%d\n", ans);
}
int main() {
#ifndef ONLINE_JUDGE
file("cpp");
#endif
int T; read(T);
while (T--) solve();
return 0;
}
「AHOI2014/JSOI2014」拼图的更多相关文章
- 「AHOI2014/JSOI2014」宅男计划
「AHOI2014/JSOI2014」宅男计划 传送门 我们首先要发现一个性质:存货天数随买食物的次数的变化类似于单峰函数. 具体证明不会啊,好像是二分加三分来证明?但是没有找到明确的严格证明. 感性 ...
- 「AHOI2014/JSOI2014」奇怪的计算器
「AHOI2014/JSOI2014」奇怪的计算器 传送门 我拿到这题首先是懵b的,因为感觉没有任何性质... 后来经过同机房dalao的指导发现可以把所有的 \(X\) 放到一起排序,然后我们可以发 ...
- 「AHOI2014/JSOI2014」骑士游戏
「AHOI2014/JSOI2014」骑士游戏 传送门 考虑 \(\text{DP}\). 设 \(dp_i\) 表示灭种(雾)一只编号为 \(i\) 的怪物的代价. 那么转移显然是: \[dp_i ...
- 「AHOI2014/JSOI2014」支线剧情
「AHOI2014/JSOI2014」支线剧情 传送门 上下界网络流. 以 \(1\) 号节点为源点 \(s\) ,新建一个汇点 \(t\),如果 \(u\) 能到 \(v\),那么连边 \(u \t ...
- 「JSOI2014」矩形并
「JSOI2014」矩形并 传送门 我们首先考虑怎么算这个期望比较好. 我们不难发现每一个矩形要和 \(n - 1\) 个矩形去交,而总共又有 \(n\) 个矩形,所以我们把矩形两两之间的交全部加起来 ...
- 「JSOI2014」打兔子
「JSOI2014」打兔子 传送门 首先要特判 \(k \ge \lceil \frac{n}{2} \rceil\) 的情况,因为此时显然可以消灭所有的兔子,也就是再环上隔一个点打一枪. 但是我们又 ...
- 「JSOI2014」电信网络
「JSOI2014」电信网络 传送门 一个点选了就必须选若干个点,最大化点权之和,显然最大权闭合子图问题. 一个点向它范围内所有点连边,直接跑最大权闭合子图即可. 参考代码: #include < ...
- 「JSOI2014」学生选课
「JSOI2014」学生选课 传送门 看到这题首先可以二分. 考虑对于当前的 \(mid\) 如何 \(\text{check}\) 我们用 \(f_{i,j}\) 来表示 \(i\) 对 \(j\) ...
- 「JSOI2014」歌剧表演
「JSOI2014」歌剧表演 传送门 没想到吧我半夜切的 这道题应该算是 \(\text{JSOI2014}\) 里面比较简单的吧... 考虑用集合关系来表示分辨关系,具体地说就是我们把所有演员分成若 ...
随机推荐
- win7安装mysql数据库
1. 软件准备,以64位系统为例如果是32位的下载32位压缩包即可] https://dev.mysql.com/downloads/mysql/ 2.下载解压到本地,将解压路径的bin目录配置到环境 ...
- CentOS7 卸载Firefox
先进入管理员模式 执行: yum remove firefox 然后用whereis 查看,却发现还是有: [root@localhost ~]# whereis firefox firefox: / ...
- CGMH:Constrained Sentence Generation by Metropolis-Hastings Sampling解读
根据关键字生成句子: 读进关键字,随机选择处理手段(增删改)以及待处理word的位置,然后计算接受/拒绝概率,根据概率生成一个新的序列,再循环这一过程,循环次数是500,每次都将困惑度最低的生成句子放 ...
- promise封装ajax
promise的含义(本身不是异步,是封装异步操作的容器,统一异步的标准) promise对象的特点:对象的状态不受外界影响:一旦状态改变,就不会再变,任何时候都可以得到这个结果. function ...
- Spring Cloud Alibaba 实战 之 Nacos 服务注册和发现
服务注册与发现,服务发现主要用于实现各个微服务实例的自动化注册与发现,是微服务治理的核心,学习 Spring Cloud Alibaba,首先要了解框架中的服务注册和发现组件——Nacos. 一.Sp ...
- .NET基础拾遗(1)类型语法基础和内存管理基础【转】
http://www.cnblogs.com/edisonchou/p/4787775.html Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理 (3)字符串 ...
- vue中watch和computed为什么能监听到数据的改变以及不同之处
先来个流程图,水平有限,凑活看吧-_-|| 首先在创建一个Vue应用时: var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' } ...
- JAVA 中集合ConcurrentMap
ConcurrentMap ConcurrentMap,它是一个接口,是一个能够支持并发访问的java.util.map集合 在原有java.util.map接口基础上又新提供了4种方法,进一步扩展了 ...
- 【代码学习】PYTHON 生成器
一.生成器 一遍循环一遍计算的机制,称为生成器 二.生成器的特点: 1.节约内存 2.迭代到下一次的调用时,所使用的参数都是第一次所保留下的,即是说,在整个所有函数调用的参数都是第一次所调用时保留的, ...
- Exception in thread "main" java.lang.UnsupportedClassVersionError: org/apache/tools/ant/launch/Launcher : Unsupported major.min
有事这么一大串错误 1.版本问题 首先看咱们的jdk安装的版本,我装的是1.7.0,但是ant下的是1.10.0版本,换成1.7.0就ok了 官网下载http://ant.apache.org 所有版 ...