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