• [UOJ#220][BZOJ4651][Noi2016]网格


    [UOJ#220][BZOJ4651][Noi2016]网格

    试题描述

    跳蚤国王和蛐蛐国王在玩一个游戏。
    他们在一个 n 行 m 列的网格上排兵布阵。其中的 c 个格子中 (0≤c≤nm),每个格子有一只蛐蛐,其余的格子中,每个格子有一只跳蚤。
    我们称占据的格子有公共边的两只跳蚤是相邻的。
    我们称两只跳蚤是连通的,当且仅当这两只跳蚤相邻,或存在另一只跳蚤与这两只跳蚤都连通。
    现在,蛐蛐国王希望,将某些(0 个,1 个或多个)跳蚤替换成蛐蛐,使得在此之后存在至少两只跳蚤不连通。
    例如:我们用图表示一只跳蚤,用图表示一只蛐蛐,那么图 1 描述了一个 n=4,m=4,c=2的情况。
    这种情况下蛐蛐国王可以通过将第 2 行第 2 列,和第 3 行第 3 列的两只跳蚤替换为蛐蛐,从而达成他的希望,如图 2 所示。并且,不存在更优的方案,但是可能存在其他替换 2 只跳蚤的方案。
    你需要首先判断蛐蛐国王的希望能否被达成。如果能够达成,你还需要最小化被替换的跳蚤的个数。
     

    输入

    每个输入文件包含多组数据。
    输入文件的第一行只有一个整数 T,表示数据的组数。保证 1≤T≤20。
    接下来依次输入 TT 组数据,每组数据的第一行包含三个整数 n, m, c。
    保证1≤n,m≤10^9,0≤c≤min(nm,105)
    接下来 c行,每行包含两个整数 x, y表示第 x 行,第 y 列的格子被一个蛐蛐占据(1≤x≤n,1≤y≤m)每一组数据当中,同一个蛐蛐不会被多次描述。
    同一行相邻的整数之间由一个空格隔开。
    1≤n,m≤10^9, 0≤c≤nm, 1≤x≤n, 1≤y≤m
    1≤T≤20。我们记 ∑c为某个测试点中,其 T 组输入数据的所有 c 的总和,∑c≤10^5

    输出

    对于每一组数据依次输出一行答案。
    如果这组数据中,蛐蛐国王的希望不能被达成,输出-1。否则,输出被替换的跳蚤的个数的最小值

    输入示例

    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)
    ", 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
    ", 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
    ", 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('
    ');
    		}*/
    		
    		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) 的。

  • 相关阅读:
    安装oracle11g 并且开启APEX 安装
    爬虫基础
    深度优先广度优先
    部署静态页面到nginx
    Nginx 实现端口转发
    五步教你实现使用Nginx+uWSGI+Django方法部署Django程序
    Please select Android SDK解决办法
    android与JS交互,互相调用方法,跳转到网页
    Android:你要的WebView与 JS 交互方式 都在这里了
    Android与js交互拍照上传资料
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/7096701.html
Copyright © 2020-2023  润新知