[UOJ#220][BZOJ4651][Noi2016]网格
[UOJ#220][BZOJ4651][Noi2016]网格
试题描述
.png)
.png)


输入
输出
输入示例
输出示例
- -
数据规模及约定
见“输入”
题解
这题数据太强了。。。再加上 UOJ 上 hack 狂魔泛滥。。。调了我一个上午,快吐血了。。。
答案只有 4 种:-1、0、1 和 2。
那么分类讨论即可
ans = -1:nm-k < 2 或 nm - k = 2 且两个空地相邻
ans = 0:不连通
ans = 1:存在割顶
ans = 2:其余情况
那么我们找出所有障碍方块往外扩两圈的空地(一个障碍最多产生 24 个空地),四联通建图即可。
对于 ans = 0 的情况,看每个障碍连通块外面的空地是否联通,注意是障碍连通块,而不是简单地每个障碍考虑一遍就行了,因为我们可以围成一个铁桶(很厚的障碍)把它卡掉,这是在 hack 数据中的第 6 组出现的。
对于 ans = 1 的情况,跑 tarjan 找割顶,注意对于每个割顶需要判断紧贴着它的周围 8 个块有没有超出边界的或是障碍点,如果没有,它就是一个“假割顶”,反例数据就是在 (1, 1) 和 (5, 5) 两个位置放上障碍,这情况是在第 7 个数据中出现的。
此外,今天还培养出一个 hash hack 狂魔 wzj。。。这就是为什么我在程序开头加了一个线性筛。。。
哦对,tarjan 求割顶时注意特判根节点。
- #include <iostream>
- #include <cstdio>
- #include <cstdlib>
- #include <cstring>
- #include <cctype>
- #include <algorithm>
- //#include <windows.h>
- using namespace std;
- int read() {
- int x = 0, f = 1; char c = getchar();
- while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
- while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
- return x * f;
- }
- #define maxn 2400010
- #define maxm 19200010
- #define MMOD 5000007
- #define X 523
- #define x first
- #define y second
- #define pii pair <int, int>
- #define mp(x, y) make_pair(x, y)
- #define RND (rand() << 15 | rand())
- #define LL long long
- int cp, prime[MMOD], MOD;
- bool Vis[MMOD];
- void init() {
- for(int i = 2; i < MMOD; i++) {
- if(!Vis[i]) prime[++cp] = i;
- for(int j = 1; i * prime[j] < MMOD && j <= cp; j++) {
- Vis[i*prime[j]] = 1;
- if(i % prime[j] == 0) break;
- }
- }
- return ;
- }
- struct Hash {
- int ToT, head[MMOD], nxt[maxn];
- pii pos[maxn];
- void init() { ToT = 0; memset(head, 0, sizeof(head)); return ; }
- int Find(pii ps) {
- int u = ((LL)ps.x * X + ps.y) % MOD;
- for(int e = head[u]; e; e = nxt[e]) if(pos[e] == ps) return e;
- return 0;
- }
- int Find(int x, int y) {
- int u = ((LL)x * X + y) % MOD;
- for(int e = head[u]; e; e = nxt[e]) if(pos[e] == mp(x, y)) return e;
- return 0;
- }
- void Insert(pii ps) {
- if(Find(ps)) return ;
- int u = ((LL)ps.x * X + ps.y) % MOD;
- nxt[++ToT] = head[u]; pos[ToT] = ps; head[u] = ToT;
- return ;
- }
- void Insert(int x, int y) {
- if(Find(x, y)) return ;
- int u = ((LL)x * X + y) % MOD;
- nxt[++ToT] = head[u]; pos[ToT] = mp(x, y); head[u] = ToT;
- return ;
- }
- } Spc, Obs;
- pii Near[maxn/24+10][30];
- int cntn[maxn/24+10];
- int dx[] = {-2, -2, -2, -2, -2, -1, -1, -1, -1, -1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, -3, 3, 0, 0},
- dy[] = {-2, -1, 0, 1, 2, -2, -1, 0, 1, 2, -2, -1, 1, 2, -2, -1, 0, 1, 2, -2, -1, 0, 1, 2, 0, 0, -3, 3},
- Dx[] = {-1, 1, 0, 0},
- Dy[] = {0, 0, -1, 1};
- struct Graph {
- int m, head[maxn], nxt[maxm], to[maxm];
- int fa[maxn];
- void init() {
- m = 0; memset(head, 0, sizeof(head));
- for(int i = 1; i <= Spc.ToT; i++) fa[i] = i;
- return ;
- }
- int findset(int x){ return x == fa[x] ? x : fa[x] = findset(fa[x]); }
- void AddEdge(int a, int b) {
- // printf("AddEdge(%d, %d)\n", a, b);
- to[++m] = b; nxt[m] = head[a]; head[a] = m;
- swap(a, b);
- to[++m] = b; nxt[m] = head[a]; head[a] = m;
- int u = findset(a), v = findset(b);
- if(u != v) fa[v] = u;
- return ;
- }
- } G;
- bool vis[maxn];
- int Q[maxn], hd, tl;
- bool BFS(int s, int setu, int n, int m) {
- hd = tl = 0; Q[++tl] = s; vis[s] = 1;
- while(hd < tl) {
- int u = Q[++hd]; pii& ps = Obs.pos[u];
- for(int i = 1; i <= cntn[u]; i++) if(G.findset(Spc.Find(Near[u][i])) != setu) return 1;
- for(int t = 0; t < 4; t++) {
- pii tp = mp(ps.x + Dx[t], ps.y + Dy[t]);
- if(1 <= tp.x && tp.x <= n && 1 <= tp.y && tp.y <= m) {
- int v = Obs.Find(tp);
- if(v && !vis[v]) Q[++tl] = v, vis[v] = 1;
- }
- }
- }
- return 0;
- }
- int low[maxn], dfn[maxn], clo;
- bool iscut[maxn];
- void dfs(int u, int fa) {
- dfn[u] = ++clo; low[u] = clo;
- // printf("__dfs: %d %d\n", u, dfn[u]);
- int son = 0;
- iscut[u] = 0;
- for(int e = G.head[u]; e; e = G.nxt[e]) if(G.to[e] != fa) {
- if(!dfn[G.to[e]]) {
- dfs(G.to[e], u);
- if(low[G.to[e]] >= dfn[u]) iscut[u] = 1;
- low[u] = min(low[u], low[G.to[e]]);
- son++;
- }
- else low[u] = min(low[u], dfn[G.to[e]]);
- }
- // printf("dfs: %d %d %d\n", u, low[u], dfn[u]);
- if(!fa && son == 1) iscut[u] = 0;
- return ;
- }
- //int Map[1010][1010];
- int main() {
- // freopen("grid7.in", "r", stdin);
- srand(20162523);
- init();
- int T = read();
- while(T--) {
- MOD = prime[RND%50000+cp-49999];
- Spc.init(); Obs.init();
- int n = read(), m = read(), c = read();
- for(int i = 1; i <= c; i++) {
- int x = read(), y = read();
- Obs.Insert(x, y);
- // Map[x][y] = 1;
- }
- if(!c) Obs.Insert(1, 0), Obs.Insert(0, 1);
- for(int i = 1; i <= Obs.ToT; i++) {
- pii& ps = Obs.pos[i];
- cntn[i] = 0;
- for(int t = 0; t < (min(n, m) > 1 ? 24 : 28); t++) {
- pii tp = mp(ps.x + dx[t], ps.y + dy[t]);
- if(1 <= tp.x && tp.x <= n && 1 <= tp.y && tp.y <= m && !Obs.Find(tp)) {
- Near[i][++cntn[i]] = tp, Spc.Insert(tp);
- // Map[tp.x][tp.y] = 2;
- }
- }
- }
- /*SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY);
- for(int i = 1; i <= n; i++) {
- for(int j = 1; j <= m; j++) {
- if(Map[i][j] == 0) printf("??");
- if(Map[i][j] == 1) printf("??");
- if(Map[i][j] == 2) {
- SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_BLUE);
- printf("??");
- SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY);
- }
- }
- putchar('\n');
- }*/
- if(c >= (LL)n * m - 1){ puts("-1"); continue; }
- G.init();
- for(int i = 1; i <= Spc.ToT; i++) {
- pii& ps = Spc.pos[i];
- for(int t = 0; t < 4; t++) {
- pii tp = mp(ps.x + Dx[t], ps.y + Dy[t]);
- if(1 <= tp.x && tp.x <= n && 1 <= tp.y && tp.y <= m && Spc.Find(tp) && Spc.Find(tp) < i)
- G.AddEdge(Spc.Find(tp), i);
- }
- }
- if(c == (LL)n * m - 2 && G.findset(1) == G.findset(2)){ puts("-1"); continue; }
- memset(vis, 0, sizeof(vis));
- bool is_0 = 0;
- for(int i = 1; i <= Obs.ToT; i++) if(!vis[i] && cntn[i]) {
- if(BFS(i, G.findset(Spc.Find(Near[i][1])), n, m)){ is_0 = 1; break; }
- }
- if(is_0){ puts("0"); continue; }
- memset(dfn, 0, sizeof(dfn)); clo = 0;
- bool is_1 = 0;
- for(int i = 1; i <= Spc.ToT; i++) if(!dfn[i]) dfs(i, 0);
- for(int i = 1; i <= Spc.ToT; i++) if(iscut[i]) {
- pii& ps = Spc.pos[i];
- for(int t = 0; t < 24; t++) if(max(abs(dx[t]), abs(dy[t])) < 2) {
- pii tp = mp(ps.x + dx[t], ps.y + dy[t]);
- if(!(1 <= tp.x && tp.x <= n && 1 <= tp.y && tp.y <= m) || Obs.Find(tp)){ is_1 = 1; break; }
- }
- if(is_1) break;
- }
- if(is_1){ puts("1"); continue; }
- puts("2");
- }
- return 0;
- }
BZOJ 不让用 time() 函数,本来随机种子是 time(0) 的。
[UOJ#220][BZOJ4651][Noi2016]网格的更多相关文章
- UOJ#220. 【NOI2016】网格 Tarjan
原文链接www.cnblogs.com/zhouzhendong/p/UOJ220.html 前言 真是一道翔题. 草率题解 -1 的情况很好判,只有两种情况: n * m - c < 2 或者 ...
- [BZOJ4651][NOI2016]网格(Tarjan)
下面直接给出结论,相关证明见官方题解. 1.若跳蚤数不超过1或仅有两只跳蚤且相邻,则答案为-1. 2.若跳蚤形成的连通块个数大于1,则答案为0. 3.若跳蚤之间建图存在割点,则答案为1. 4.否则为2 ...
- BZOJ4651 NOI2016网格(割点)
首先显然可以通过孤立角落里的跳蚤使其不连通,所以只要有解答案就不会大于2.同样显然的一点是当且仅当跳蚤数量<=2且连通时无解.做法其实也很显然了:特判无解,若跳蚤不连通输出0,否则看图中是否无割 ...
- [UOJ#223][BZOJ4654][Noi2016]国王饮水记
[UOJ#223][BZOJ4654][Noi2016]国王饮水记 试题描述 跳蚤国有 n 个城市,伟大的跳蚤国王居住在跳蚤国首都中,即 1 号城市中.跳蚤国最大的问题就是饮水问题,由于首都中居住的跳 ...
- [UOJ#221][BZOJ4652][Noi2016]循环之美
[UOJ#221][BZOJ4652][Noi2016]循环之美 试题描述 牛牛是一个热爱算法设计的高中生.在他设计的算法中,常常会使用带小数的数进行计算.牛牛认为,如果在 k 进制下,一个数的小数部 ...
- [UOJ#219][BZOJ4650][Noi2016]优秀的拆分
[UOJ#219][BZOJ4650][Noi2016]优秀的拆分 试题描述 如果一个字符串可以被拆分为 AABBAABB 的形式,其中 A 和 B 是任意非空字符串,则我们称该字符串的这种拆分是优秀 ...
- BZOJ4651 & 洛谷1173 & UOJ220:[NOI2016]网格——题解(附debug数据)
https://www.lydsy.com/JudgeOnline/problem.php?id=4651 https://www.luogu.org/problemnew/show/P1173#su ...
- BZOJ4651/UOJ220 [Noi2016]网格
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- 并不对劲的bzoj4651:loj2084:uoj220:p1173:[NOI2016]网格
题目大意 有一个\(n*m\)(\(n,m\leq10^9\))的网格,每个格子是空地或障碍(\(障碍数\leq10^5\)) 定义两块空地连通,当且仅当它们是"相邻的两块空地"或 ...
随机推荐
- 【Web应用-网络连接】Azure Web 应用对外连接数上限分析
在 Azure Web 应用中发起大量外部连接操作时,需要考虑已经建立了多少外部连接.当超过最大对外连接数时,Azure Web 应用将会产生套接字异常.Azure Web 应用对于各个级别的实例,对 ...
- codevs 3278 最小m 段和问题
时间限制: 1 s 空间限制: 256000 KB 题目等级 : 黄金 Gold 题目描述 Description 给定 n 个整数(不一定是正整数)组成的序列,现在要求将序列分割为 m 段,每段 ...
- 仿天猫淘宝的ShopNC好商城原生Android 客户端源码项目
开发环境:Android Studio 2.0 | Gradle 2.0.0最后更新:2016-04-28 简介:基于好商城V4的Android客户端 目前已完成的功能(概述): 1.启动页 -> ...
- 根据HTML语义化编码
语义化标签——http://www.html5jscss.com/html5-semantics-section.html 写HTML代码时应注意什么? 尽可能少的使用无语义的标签div和span: ...
- 14.list列表
1).列表的切片 li = ['德玛西亚',[1,2,3],'luokesasi','eson','女神','jingdongi'] l1 = li[0] print(l1) #>>> ...
- HTML5服务器发送事件(Server-Send Events)
HTML5服务器发送事件是允许获得来自服务器的更新. server-sent事件-单向传递消息,表示网页自动获取来自服务器的更新. 其中有一个重要的对象,eventsource对象是用来接收服务器发送 ...
- 概述「并查集补集转化」模型&&luoguP1330 封锁阳光大学
奇妙的模型转化以及并查集思想 模型概述 有图$G=(V,E)$,初始所有点为白色,现在要将其中一些点染为黑色,要求染色后满足:$∀(u,v)∈E$,$∃col_u!=col_v$.求最小染色点数. 题 ...
- [UVA] 704 Colour Hash
所谓"周界搜索",练习搜索的好题,双向宽搜/迭代加深均可,还有很多细节有待完善,判重有比set更优的结构,宽搜还没写,先存一下. //Writer:GhostCai &&a ...
- 【OS_Linux】Linux系统中目录及文件管理
1.Linux系统中目录的树状结构 目录 /bin 存放二进制可执行文件(ls,cat,mkdir等),常用命令一般都在这里. /etc 存放系统管理和配置文件 /home 存放所有用户文件的根目录, ...
- 微信开发 access_token 数量限制问题
微信对access_token的请求有数量限制, 如果用户量特别多的话, access_token 可能会不够用 两种方案: 1. access_token 加入缓存并设置2小时的失效时间,每次从 ...