题面

题解

(题目中说的四种摆放方式实际上是分别旋转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形覆盖 - (图论、简单推导)的更多相关文章

  1. [LOJ#2326]「清华集训 2017」简单数据结构

    [LOJ#2326]「清华集训 2017」简单数据结构 试题描述 参加完IOI2018之后就是姚班面试.而你,由于讨厌物理.并且想成为乔布斯一样的创业家,被成功踢回贵系. 转眼,时间的指针被指向201 ...

  2. MyISAM和innoDB对比,覆盖索引简单回顾

    MyISAM Myisam是Mysql的默认存储引擎,当create创建新表时,未指定新表的存储引擎时,默认使用Myisam. 它不支持事务,也不支持外键,尤其是访问速度快,对事务完整性没有要求或者以 ...

  3. OI图论 简单学习笔记

    网络流另开了一个专题,所以在这里就不详细叙述了. 图 一般表示为\(G=(V,E)\),V表示点集,E表示边集 定义图G为简单图,当且仅当图G没有重边和自环. 对于图G=(V,E)和图G2=(V2,E ...

  4. 模拟赛38 B. T形覆盖 大模拟

    题目描述 如果玩过俄罗斯方块,应该见过如下图形: 我们称它为一个 \(T\) 形四格拼板 .其中心被标记为\(×\). 小苗画了一个 \(m\) 行 \(n\) 列的长方形网格.行从 \(0\) 至 ...

  5. 剑指offer-矩形覆盖10

    题目描述 我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形.请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? # -*- coding:utf-8 -*- class S ...

  6. JZ-010-矩形覆盖

    矩形覆盖 题目描述 我们可以用21的小矩形横着或者竖着去覆盖更大的矩形.请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? 题目链接: 矩形覆盖 代码 /** * 标题:矩形覆盖 ...

  7. 剑指offer-矩形覆盖-斐波那契数列(递归,递推)

    class Solution { public: int rectCover(int number) { if(number==0 || number==1||number==2) return nu ...

  8. 贝塞尔曲线.简单推导与用opengl实现动态画出。

    在opengl中,我们可以用少许的参数来描述一个曲线,其中贝塞尔曲线算是一种很常见的曲线控制方法,我们先来看维基百科里对贝塞尔曲线的说明: 线性贝塞尔曲线 给定点P0.P1,线性贝塞尔曲线只是一条两点 ...

  9. Python学习3——Python的简单推导

    列表推导是一种从其他列表创建列表的方式,类似于数学中的集合推导,列表推导的工作原理非常简单,类似于for循环.(以下代码均在IDLE实现) 最简单的列表推导: >>>[x*x for ...

随机推荐

  1. 27.MySQL 索引、事务与存储引擎

    MySQL 索引.事务与存储引擎 目录 MySQL 索引.事务与存储引擎 MySQL 索引 索引的概念 索引的作用及副作用 索引的作用 索引的副作用 创建索引的原则依据 索引的分类和创建 普通索引 唯 ...

  2. orcal恢复delete误删除的数据

    orcal的删除有3种:delete.truncate.drop. delete可以手动提交和回滚,且可以使用where:而truncate.drop执行即对表数据进行了修改,且不能使用where. ...

  3. Spring jdbctemplate和事务管理器

    内部bean 对象结构: @Autowiredprivate IAccountService accountService; @Service("accountService")@ ...

  4. ansible安装配置及基本用法

    ansiblle具有如下特点: 1.部署简单,只需在主控端部署Ansible环境,被控端无需做任何操作: 2.默认使用SSH协议对设备进行管理: 3.主从集中化管理: 4.配置简单.功能强大.扩展性强 ...

  5. 20行python代码,轻松获取各路小说,非常简单

    哔哔两句 作为现代青年,我相信应该没几个没看过小说的吧,嘿嘿~ 一般来说咱们书荒的时候怎么办?自然是去起某点排行榜先找到小说名字,然后再找度娘一搜,哎 ,笔趣阁就出来答案了,美滋滋~但是那多麻烦,咱们 ...

  6. Nacos配置失败(java.lang.IllegalStateException: failed to req API:/nacos/v1/ns/instance after all server)

    解决: nacos服务器过载,可以删掉nacos文件夹下的data文件夹,重新启动.

  7. 没想到吧,Spring中还有一招集合注入的写法

    原创:微信公众号 码农参上,欢迎分享,转载请保留出处. 哈喽大家好啊,我是Hydra. Spring作为项目中不可缺少的底层框架,提供的最基础的功能就是bean的管理了.bean的注入相信大家都比较熟 ...

  8. 深入解析Kubernetes admission webhooks

    BACKGROUND admission controllers的特点: 可定制性:准入功能可针对不同的场景进行调整. 可预防性:审计则是为了检测问题,而准入控制器可以预防问题发生 可扩展性:在kub ...

  9. while and do while

    package study5ran2yl.study; public class deno14 { public static void main(String[] args) { //计算1+2+. ...

  10. 本机通过IP地址连接Ubuntu18.04+ on Vmware

    一.Vmware-顶部菜单栏-编辑-虚拟网络编辑器: 点一下 添加一个NAT模式的网络:要记住名称,比如这里我的是VMnet8 子网ip可以自己写,建议全程就都按我这个写,后续方便校对. 点一下 NA ...