To spread over the riverbeds so dry and dead

QOJ 18211 扫雷

第一次做通信喵

先补点知识吧。

关于通信

就是说,你的程序要跑两次,第一次跑的结果会有部分成为第二次的信息,而且通常可以传一点很短的,额外的信息,题目要求你还原第一次的隐藏信息。

关于平面图

有个优美的性质:边的数量是 \(3n\) 级别的,并且不到 \(3n\) 一点。

这导致了度数的和是 \(6n\) 级别的,也就是说,平面图是存在一种方式,使得每一次删除度数最小的点,删除时的最小的那个点的度数 \(\le 5\)。

解题思路

正片。考虑每一次只删除度数 \(\le 5\) 的点,显然是可以删完整张图的。

因此我们在第一次和第二次都按这种方式删,显然的,如果我们发现剩下的炸弹数量反映的是 \(>5\) 或者 \(<0\),那么就肯定是有问题的。

于是我们得到了每一个炸弹的禁止使用的 \(a\) 的范围,然后发现这样子至多会有 \(6\) 个炸弹无法选中。考虑怎么解决。考虑第一个被移除的炸弹,必然是 \([0,5]\) 的范围禁止选中,因此其限制是 \(5\) 的大小,于是在这种情况下,我们就只会剩下 \(5\) 个炸弹的参数需要传了。

每一个炸弹的编号需要 \(19\) 位,显然可以解决。

Code

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define File(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout)
#define LL long long
#define fi first
#define se second
const int N = 5e5 + 10;
namespace solve1{
int a[N],b[N],c[N],n,m,k,mp[N],deg[N],vis[N];
deque<int> p;
vector<int> G[N];
char s[105];
void solve(){
	for(int i=0;i<=100;i++)
		s[i] = '0';
	cin >> n >> m >> k;
	p.clear();
	for(int i=1;i<=m;i++){
		int u,v;
		cin >> u >> v;
		G[u].push_back(v);G[v].push_back(u);
		deg[u] ++ ;deg[v] ++ ;
	}
	for(int i=1;i<=k;i++){ cin >> b[i]; mp[b[i]] = 1;}
	for(int i=1;i<=k;i++)
		p.push_back(i);
	queue<int> q;
	for(int i=1;i<=n;i++)
		if(deg[i] <= 5){ q.push(i); vis[i] = 1; }
	int cnt = 0;
	vector<int> vec;
	while(!q.empty()){
		int u = q.front();
		q.pop();
		if(mp[u]){
			if(cnt == 0){
				vec.push_back(u);
				cnt ++ ;
			}
			else{
				int L = c[u];int R = c[u] + 5;
				if(p.front() < L){
					a[u] = p.front();
					p.pop_front();
				}
				else if(p.back() > R){
					a[u] = p.back();
					p.pop_back();
				}
				else vec.push_back(u);
			}
			for(int v : G[u]){
				if(vis[v]) continue;
				deg[v] -- ;
				c[v] ++ ;
				if(deg[v] <= 5){vis[v] = 1;q.push(v);}
			}
		}
		else{
			for(int v : G[u]){
				if(mp[v]) a[u] ++ ;
				if(vis[v]) continue;
				deg[v] -- ;
				if(deg[v] <= 5){vis[v] = 1;q.push(v);}
			}
		}
	}
	int tot = vec.size() - 1;
	int be = 0;
	if(vec.size() > 5){
		be = 1;
		int id = vec[0];
		int L = 1,R = 5;
		if(p.front() < L){
			a[id] = p.front();
			p.pop_front();
		}
		else if(p.back() > R){
			a[id] = p.back();
			p.pop_back();
		}
	}	
	for(int i=be;i<vec.size();i++){
		int u = vec[i];
		a[u] = p.front();p.pop_front();
	}
	for(int j=0;j<=2;j++){
		s[j] = ((tot & 1) + '0');
		tot >>= 1;
	}
	for(int i=3,k=be;k<vec.size();i+=19,k++){
		int u = vec[k];
		for(int j=0;j<19;j++){
			s[i+j] = ((u & 1) + '0');
			u >>= 1;
		}
	}
	for(int i=1;i<=n;i++)
		cout << a[i] << " ";
	cout << '\n';
	for(int i=0;i<=99;i++)
		cout << s[i];
	cout << "\n";
	for(int i=0;i<=100;i++)
		s[i] = '0';
	for(int i=1;i<=n;i++){
		a[i] = c[i] = deg[i] = mp[i] = vis[i] = 0;
		G[i].clear();
	}
	return ;
}
}
namespace solve2{
int n,m,k;
char s[N];
vector<int> G[N];
int c[N];
int mp[N],deg[N],a[N],vis[N];
void solve(){
	cin >> n >> m;
	k = 0;
	for(int i=1;i<=m;i++){
		int u,v;cin >> u >> v;
		G[u].push_back(v);
		G[v].push_back(u);
		deg[u] ++ ; deg[v] ++ ;
	}
	for(int i=1;i<=n;i++) cin >> a[i];
	for(int i=0;i<=99;i++) cin >> s[i];
	int tot = 0;
	for(int i=0;i<=2;i++)
		tot += (s[i] - '0') * (1 << i);
	for(int i=3;i<99;i+=19){
		if(i + 18 >= 99) break;
		int x = 0;
		for(int j=0;j<19;j++)
			x += (s[i+j] - '0') * (1 << j);
		if(x > 0) mp[x] = 1;
	}
	queue<int> q;
	for(int i=1;i<=n;i++){ if(deg[i] <= 5) {q.push(i); vis[i] = 1;}}
	while(!q.empty()){
		int u = q.front();
		q.pop();
		int L = c[u],R = c[u] + 5;
		if(a[u] < L || a[u] > R) mp[u] = 1;
		for(int v : G[u]){
			if(vis[v]) continue;
			deg[v] -- ;
			c[v] += mp[u];
			if(deg[v] <= 5){
				vis[v] = 1;
				q.push(v);
			}
		}
	}
	for(int i=1;i<=n;i++)
		k += mp[i];
	cout << k << "\n";
	for(int i=1;i<=n;i++)
		if(mp[i]) cout << i << " ";
	cout << "\n";
	for(int i=1;i<=n;i++){
		c[i] = deg[i] = mp[i] = vis[i] = 0;
		G[i].clear();
	}
}
}
int main(){
	IOS;
	int r,T;
	cin >> r >> T;
	while(T -- )
		if(r == 1) solve1::solve();
		else solve2::solve();
	return 0;
}
posted @ 2026-09-24 08:42  WinterXorSnow  阅读(11)  评论(0)    收藏  举报