[UOJ#220][BZOJ4651][Noi2016]网格
Posted xjr_01
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[UOJ#220][BZOJ4651][Noi2016]网格相关的知识,希望对你有一定的参考价值。
[UOJ#220][BZOJ4651][Noi2016]网格
试题描述
输入
输出
输入示例
4 4 4 2 1 1 4 4 2 3 1 1 2 2 2 2 1 1 2 2 1 1 0
输出示例
2 1 0 -1
数据规模及约定
见“输入”
题解
这题数据太强了。。。再加上 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#129][BZOJ4197][Noi2015]寿司晚宴
[UOJ#130][BZOJ4198][Noi2015]荷马史诗
BZOJ4942 & UOJ314:[NOI2017]整数——题解
[UOJ#127][BZOJ4195][NOI2015]程序自动分析