其他分享
首页 > 其他分享> > Codeforces Round #805 (Div. 3)

Codeforces Round #805 (Div. 3)

作者:互联网

比赛链接:

https://codeforces.com/contest/1702

E. Split Into Two Sets

题意:

\(n\)(\(n\) 为偶数)张多米诺骨牌,每张骨牌有两个数字(数字范围为 1 到 \(n\)),问是否能将所有的骨牌分成两堆,每堆中的数字没有重复。

思路:

容易知道最后划分出来的两堆骨牌覆盖了 1 到 \(n\) 的所有数字,即每个数字在每堆中只有一个。
所以可以将所有的数字对应的骨牌编号记录下来,同一个数字对应的两张骨牌要不在一个堆中,满足二分图的性质。
将一张骨牌所对应的两个编号之间建立一条边,通过染色法判断是不是二分图。

#include <bits/stdc++.h>
using namespace std;
#define LL long long
void solve(){
	LL n;
	cin >> n;
	vector <LL> g[n + 1], cnt(n + 1), G[n + 1];
	bool ok = true;
	for (int i = 0; i < n; i ++ ){
		LL a, b;
		cin >> a >> b;
		g[a].push_back(i);
		g[b].push_back(i);
		if (a == b){
			ok = false;
		}
		cnt[a] ++ ;
		cnt[b] ++ ;
		if (cnt[a] >= 3 || cnt[b] >= 3){
			ok = false;
		}
	}
	if (!ok){
		cout << "NO\n";
		return;
	}
	for (int i = 1; i <= n; i ++ ){  //建图
		LL u = g[i][0], v = g[i][1];
		G[u].push_back(v);
		G[v].push_back(u);
	}
	vector <LL> color(n + 1);
	function<bool(LL, LL)> dfs = [&] (LL u, LL c){  //染色法判断二分图
		color[u] = c;
		for (auto v : G[u]){
			if (!color[v]){
				if (!dfs(v, 3 - c))
					return false;
			}
			else{
				if (color[v] == c){
					return false;
				}
			}
		}
		return true;
	};
	for (int i = 1; i <= n; i ++ ){
		if (!color[i]){
			if (!dfs(i, 1)){
				cout << "NO\n";
				return;
			}
		}
	}
	cout << "YES\n";
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	LL T;
	cin >> T;
	while(T -- )
		solve();
	return 0;
}

让骨牌对应的两个数字产生联系,它们最后会形成一个环,要做的就是将这个环拆成两段,分别放到两个堆中,即环的长度为偶数,所以可以通过并查集来做,判断每个环的长度即可。

#include <bits/stdc++.h>
using namespace std;
#define LL long long
struct dsu{
	LL n;
	vector <LL> p, sz;
	dsu(LL n) : n(n){
		p.resize(n + 1);
		sz.resize(n + 1);
		iota(p.begin(), p.end(), 0LL);
		for (int i = 1; i <= n; i ++ )
			sz[i] = 1;
	}
	LL get(LL x){
		return (x == p[x] ? x : (p[x] = get(p[x])));
	}
	void unite(LL x, LL y){
		x = get(x);
		y = get(y);
		if (x != y){
			p[x] = y;
			sz[y] += sz[x];
		}
	}
};
void solve(){
	LL n;
	cin >> n;
	dsu d(n);
	vector <LL> cnt(n + 1);
	bool ok = true;
	for (int i = 0; i < n; i ++ ){
		LL x, y;
		cin >> x >> y;
		cnt[x] ++ ;
		cnt[y] ++ ;
		if (x == y){
			ok = false;
		}
		d.unite(x, y);
	}
	if (!ok){
		cout << "NO\n";
		return;
	}
	for (int i = 1; i <= n; i ++ ){
		if (cnt[i] != 2){
			cout << "NO\n";
			return;
		}
	}
	for (int i = 1; i <= n; i ++ ){
		if (i != d.get(i)){
			if (d.sz[d.get(i)] & 1){
				cout << "NO\n";
				return;
			}
		}
	}
	cout << "YES\n";
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	LL T;
	cin >> T;
	while (T -- )
		solve();
	return 0;
}

F. Equate Multisets

题意:

给定两个序列 \(a\) 和 \(b\),可以选择 \(b\) 中的元素进行除 2 或者乘 2 操作,问是否能让 \(b\) 与 \(a\) 中的元素相同。

思路:

对于一个元素 * 2 是不会改变奇偶性的,但是 / 2 可能会改变,可以将所有的偶数中的 2 全部去掉,这样子所有的元素就都是奇数了。
能够匹配的元素进行匹配,不能够匹配的一直 / 2,直到不能除为止,若始终无法匹配,说明没有办法让两个序列元素相同。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
void solve(){
	LL n;
	cin >> n;
	map <LL, LL> cnt;
	for (int i = 0; i < n; i ++ ){
		LL x;
		cin >> x;
		while(x % 2 == 0){
			x >>= 1;
		}
		cnt[x] ++ ;
	}
	vector <LL> b(n);
	for (int i = 0; i < n; i ++ ){
		cin >> b[i];
		while(b[i] % 2 == 0){
			b[i] >>= 1;
		}
	}
	for (int i = 0; i < n; i ++ ){
		while(cnt[b[i]] == 0 && b[i] > 0){
			b[i] /= 2;
		}
		if (b[i] == 0){
			cout << "NO\n";
			return;
		}
		cnt[b[i]] -- ;
	}
	cout << "YES\n";
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	LL T;
	cin >> T;
	while(T -- )
		solve();
	return 0;
}

标签:cnt,ok,++,LL,Codeforces,int,骨牌,Div,805
来源: https://www.cnblogs.com/Hamine/p/16465518.html