【LOJ#3197】【eJOI2019】T形覆盖 - (图论、简单推导)
题面

题解
(题目中说的四种摆放方式实际上是分别旋转0°,90°,180°,270°后的图形)
题目中关于摆放方式的描述听起来很臭,我们把它转换一下,每个拼版先覆盖“上下左右中”五个格子,然后再在四个相邻格子中减去一个。
那么我们先把每个拼版所在“十字”涂了,然后把有重复涂过的格子当成边,把拼版们通过这些边连起来,成为许多个连通块,不同连通块之间肯定是互不干扰的,可以独立计算贡献。
如下图(我用颜色的中和表示被涂多次,很好理解吧),A、B、C是连通块,注意,D不是连通块,这也是遍历的时候需要注意的情况。

对于每个连通块,里面都会有至少一个的被涂了大于等于两遍的格子,如果有被涂了三遍甚至四遍的格子,那么直接输出No,这比较显然,自己想想就知道了。
由于接下来每个拼版要在相邻的格子中减去一个,即让相邻的一个格子被涂次数-1,所以把每个连通块被涂多次的格子数数出来,记为 E(其实就是边数),把拼版数记为 N(其实就是点数),我们会发现以下结论:
- 若 E > N ,由于一个点可以使 E 减 1 ,N 个就可以减 N,所以 E - N > 0 意味着什么?无论如何连通块内都会存在被重复覆盖的格子,即无解,输出No
- 若 E == N,即 E - N == 0,刚好可以把重复格子清完,即为环或基环树,就如上图的A、B、C(A、B也是刚好相等的!也就是说“两个点可以有重边”),也就是说答案就是这个连通块覆盖的所有格子中的数的和,不多不少
- 若 E < N,此时只可能是 E == N-1,即为一个树状图,此时不仅可以把被涂的多余层全消完(此多余层可以为拼版中心格子),还可以多消一个非拼版中心的格子(包括先前被涂多次,后来被消成单层的格子),然后,任何连通块内这样的格子都可以被选择作为多消掉的一个,为什么呢?因为它是树形结构,所以相邻两块拼版最多有一个格子重复覆盖(不然超过一个就有环了嘛),把任意一个可消的格子选择后,所在的一个或两个拼版状态就确定了,就可以顺推出整棵树的每个拼版的状态,而且可以证明是一定有解的!……
……只不过你得特殊处理一下贴墙的情况,不过不影响结论。
至于怎么DFS,只用模拟走边,跑图,然后计算覆盖的格子的信息就行了。如果是 E < N ,就选一个权值最小的可选格子令ans减去它即可。注意ans是最早先不重复地把覆盖的所有格子的数加进去了的。
复杂度O(nm)
CODE
如果测大数据时运行爆了,不用怕,开无限栈应该就解决了
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 1000005
#define LL long long
#define DB double
#define ENDL putchar('\n')
#define lowbit(x) ((-x) & (x))
LL read() {
LL f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f * x;
}
const int MOD = 1000000007;
int n,m,i,j,s,o,k;
vector<int> a[MAXN];
int c[MAXN],d[MAXN];
bool f[MAXN];
bool Out(int x,int y) {return x < 1 || y < 1 || x > n || y > m;}
int cg(int x,int y) {return max(0,min((x-1)*m+y,n*m+1));}
struct it{
int x,y;
}p[MAXN];
int md,cn,flag,mi,cnt;
void dfs(int x,int y) {
if(!flag || Out(x,y) || f[cg(x,y)] || (!c[cg(x,y)])) return ;
f[cg(x,y)] = 1;
if(c[cg(x,y)] > 2) {
flag = 0; return ;
}
if(c[cg(x,y)] == 2) md ++;
if(d[cg(x,y)]) {
cn ++;
if(Out(x-1,y)) md ++;
if(Out(x+1,y)) md ++;
if(Out(x,y+1)) md ++;
if(Out(x,y-1)) md ++;
}
else mi = min(mi,a[x][y]);
if(c[cg(x,y)] == 2) {
if(!Out(x-1,y) && d[cg(x-1,y)]) dfs(x-1,y);
if(!Out(x+1,y) && d[cg(x+1,y)]) dfs(x+1,y);
if(!Out(x,y-1) && d[cg(x,y-1)]) dfs(x,y-1);
if(!Out(x,y+1) && d[cg(x,y+1)]) dfs(x,y+1);
}
else if(d[cg(x,y)]) {
dfs(x-1,y);dfs(x+1,y);
dfs(x,y-1);dfs(x,y+1);
}
return ;
}
int solve(int x,int y) {
mi = 0x7f7f7f7f;
md = cn = 0;
dfs(x,y);
if(md > cn || !flag) {
flag = 0;return 0;
}
if(md == cn) return 0;
if(md < cn) return mi;
return 0;
}
int main() {
freopen("t-covering.in","r",stdin);
freopen("t-covering.out","w",stdout);
n = read(); m = read();
for(int i = 1;i <= n;i ++) {
a[i].push_back(0);
for(int j = 1;j <= m;j ++) {
a[i].push_back(read());
}
}
k = read();
for(int i = 1;i <= k;i ++) {
s = p[i].x = read()+1;o = p[i].y = read()+1;
c[cg(s,o)] ++; d[cg(s,o)] ++;
if(s > 1) c[cg(s-1,o)] ++;
if(s < n) c[cg(s+1,o)] ++;
if(o > 1) c[cg(s,o-1)] ++;
if(o < m) c[cg(s,o+1)] ++;
}
LL ans = 0;
flag = 1;
for(int i = 1;i <= n;i ++) {
for(int j = 1;j <= m;j ++) {
if(c[cg(i,j)]) {
ans += a[i][j];
}
if(d[cg(i,j)] && !f[cg(i,j)]) {
ans -= solve(i,j);
}
if(!flag) {
printf("No\n");
return 0;
}
}
}
printf("%lld\n",ans);
return 0;
}
【LOJ#3197】【eJOI2019】T形覆盖 - (图论、简单推导)的更多相关文章
- [LOJ#2326]「清华集训 2017」简单数据结构
[LOJ#2326]「清华集训 2017」简单数据结构 试题描述 参加完IOI2018之后就是姚班面试.而你,由于讨厌物理.并且想成为乔布斯一样的创业家,被成功踢回贵系. 转眼,时间的指针被指向201 ...
- MyISAM和innoDB对比,覆盖索引简单回顾
MyISAM Myisam是Mysql的默认存储引擎,当create创建新表时,未指定新表的存储引擎时,默认使用Myisam. 它不支持事务,也不支持外键,尤其是访问速度快,对事务完整性没有要求或者以 ...
- OI图论 简单学习笔记
网络流另开了一个专题,所以在这里就不详细叙述了. 图 一般表示为\(G=(V,E)\),V表示点集,E表示边集 定义图G为简单图,当且仅当图G没有重边和自环. 对于图G=(V,E)和图G2=(V2,E ...
- 模拟赛38 B. T形覆盖 大模拟
题目描述 如果玩过俄罗斯方块,应该见过如下图形: 我们称它为一个 \(T\) 形四格拼板 .其中心被标记为\(×\). 小苗画了一个 \(m\) 行 \(n\) 列的长方形网格.行从 \(0\) 至 ...
- 剑指offer-矩形覆盖10
题目描述 我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形.请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? # -*- coding:utf-8 -*- class S ...
- JZ-010-矩形覆盖
矩形覆盖 题目描述 我们可以用21的小矩形横着或者竖着去覆盖更大的矩形.请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? 题目链接: 矩形覆盖 代码 /** * 标题:矩形覆盖 ...
- 剑指offer-矩形覆盖-斐波那契数列(递归,递推)
class Solution { public: int rectCover(int number) { if(number==0 || number==1||number==2) return nu ...
- 贝塞尔曲线.简单推导与用opengl实现动态画出。
在opengl中,我们可以用少许的参数来描述一个曲线,其中贝塞尔曲线算是一种很常见的曲线控制方法,我们先来看维基百科里对贝塞尔曲线的说明: 线性贝塞尔曲线 给定点P0.P1,线性贝塞尔曲线只是一条两点 ...
- Python学习3——Python的简单推导
列表推导是一种从其他列表创建列表的方式,类似于数学中的集合推导,列表推导的工作原理非常简单,类似于for循环.(以下代码均在IDLE实现) 最简单的列表推导: >>>[x*x for ...
随机推荐
- SQL的语法
SQL的语法 SQL通用语法 SQL语句可以单行或多行书写,以分号(";")结尾. SQL语句可以使用空格或缩进增强可读性. MySQL数据库的SQL语句不区分大小写(建议关键字大 ...
- VmWare安装Centos8注意事项
VmWare安装Centos8注意事项 1.需选择稍后安装操作系统 2.选择操作系统版本 3.修改虚拟机配置 4.配置完成点击开启虚拟机(注意要将鼠标放在屏幕中央,点击一下后才能使用上下键进行选择) ...
- c++可视化性能测试
阅读前注意 本文所有代码贴出来的目的是帮助大家理解,并非是要引导大家跟写,许多环境问题文件问题没有详细说明,代码也并不全面,达不到跟做的效果.建议直接阅读全文即可,我在最后会给出详细代码地址,对源代码 ...
- JS:typeof
想要弄明白某一个变量中保存的数据到底是什么数据类型,我们可以使用到typeof操作符. typeof操作符:检测变量的数据类型. 看例子! var a = "abc"; var b ...
- 缤纷多彩的WPF样式框架,开源项目
下面介绍的四种主流样式框架(最近项目需要,所以了解了一些),在Nuget及Github均可以找到~ 首推样式框架MahApp.Metro 再推样式框架ModernUI 三推样式框架MaterialDe ...
- 【python基础】第06回 运算符和流程控制 1
本章内容概要 1.运算符 2.流程控制 本章内容详解 1.运算符 什么是运算符? 运算符用于执行程序代码运算,会针对一个以上操作数项目来进行运算.例如:2+3,其操作数是2和3,而运算符则是" ...
- Mysql错误:The server time zone value is unrecognized or represents more than one time zone
方法1.修改Mysql的时区为东8区,执行如下命令即可: PS:这种方式每次开机都要配置的 set global time_zone='+8:00' 方法2.配置改成这样的 spring.dataso ...
- css-sticky 定位
前言 我们大多都了解绝对定位.相对定位.static 和 fixed 定位,而 sticky 定位常常会被忽略,本文来总结一下其相关使用方法. 正文 1.常见使用效果 我们滚动滚动条时,当 " ...
- 【cartogarpher_ros】一: ros系统下的快速安装
Cartographer是一个跨多个平台和传感器配置提供 2D 和 3D实时同步定位和映射 ( SLAM ) 的系统. 使用Cartographer有Ros集成环境和无Ros环境,对于新手快速入门,推 ...
- MySQL经典50题
1.查询01课程比02课程成绩高的学生的信息及课程分数 #1.1查询01课程与02课程的课程表: select student_id, score as c1_score from score whe ...