题意:要在一张网格纸上画出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. C# 委托还能这样用

    一直找不到一种能够让很多对象都能在几乎同时接收到通知的方法.介绍下目前在用的,希望能够抛砖引玉. 首先随便贴一下观察者模式的两接口,观察者模式自行搜索设计模式. public interface IS ...

  2. Nginx日志常用统计分析命令

    IP相关统计 统计IP访问量(独立ip访问数量) awk '{print $1}' access.log | sort -n | uniq | wc -l 查看某一时间段的IP访问量(4-5点) gr ...

  3. Dynamics 365中的批量删除作业执行频率可以高于每天一次吗?

    微软动态CRM专家罗勇 ,回复317或者20190314可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me!我的网站是 www.luoyong.me . 我先来做一个例子,登 ...

  4. 章节十、3-CSS Selector---用CSS Selector - ID定位元素

    一.如果元素的 ID 不唯一,或者是动态的,或者 name 以及 linktext 属性值也不唯一,对于这样的元素,我们 就需要考虑用 xpath或者css selector 来查找元素了,然后再对元 ...

  5. 好代码是管出来的——.Net Core集成测试与数据驱动测试

    软件的单元测试关注是的软件最小可执行单元是否能够正常执行,但是软件是由一个个最小执行单元组成的集合体,单元与单元之间存在着种种依赖或联系,所以在软件开发时仅仅确保最小单元的正确往往是不够的,为了保证软 ...

  6. C# ToString()日期格式

    C# ToString()日期格式 ToString:2016/9/27 0:00:00ToString("yyyy/MM/dd"):2016/09/27ToString(&quo ...

  7. SQL Server系统表sysobjects介绍

    SQL Server系统表sysobjects介绍 sysobjects 表结构: 列名 数据类型 描述 name sysname 对象名,常用列 id int 对象标识号 xtype char(2) ...

  8. liteos简介(一)

    LiteOS是在2015华为网络大会上华为发布的敏捷网络3.0中的一个轻量级的物联网操作系统,LiteOS体积只有10KB级. 在Hi3559A中,liteos是用于Cortex-A53,用于处理MP ...

  9. Linux(Manjaro) - Docker - MySQL 安装配置

    Linux(Manjaro) - Docker - MySQL 安装配置 拉取mysql镜像 # 使用网易的 MySQL 镜像地址 docker pull hub.c.163.com/library/ ...

  10. Python之爬虫的理解

    #  -*- coding: utf-8 -*-  中文用户一定先用这行来声明编码方式 爬虫: 爬虫是自动访问互联网,并且提取数据的程序  (从网络上获取非结构化的数据,ETL将这些数据转换为结构化数 ...