Codeforces 847 Div3 题解A-G
Posted tiany7
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces 847 Div3 题解A-G相关的知识,希望对你有一定的参考价值。
Codeforces 847 Div3 题解A-G
好久不打了,这几周忙着写各种作业,然后发现代码力跟不上了。今天复健一下吧。反正也是比较碎片的时间,马上新的作业就会被布置下来,n久没打了就来看下。所以这次先捡div3复键一下,之后暑假等实习了到时候得认真上上div2,不然秋招g咯。
A. Polycarp and the Day of Pi
这个题题意给出一个1-30位string,问猜圆周率的人猜对了几位
这个本来想用acos(-1)按照位进行比对,后来发现题目中给了圆周率的前30位,那这题就是白送了。
AC 代码
#include <bits/stdc++.h>
using namespace std;
constexpr int limit = (4e5 + 5);//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-9
#define FASTIO ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define pi(a, b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a ; --i)
#define MOD 998244353
#define traverse(u) for(int i = head[u]; ~i ; i = edge[i].next)
#define FOPEN freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
inline ll read()
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
ll sign = 1, x = 0;
char s = getchar();
while (s > \'9\' || s < \'0\')
if (s == \'-\')sign = -1;
s = getchar();
while (s >= \'0\' && s <= \'9\')
x = (x << 3) + (x << 1) + s - \'0\';
s = getchar();
return x * sign;
#undef getchar
//快读
void print(ll x)
if (x / 10) print(x / 10);
*O++ = x % 10 + \'0\';
void write(ll x, char c = \'t\')
if (x < 0)putchar(\'-\'), x = -x;
print(x);
if (!isalpha(c))*O++ = c;
fwrite(obuf, O - obuf, 1, stdout);
O = obuf;
int n,m;
int a[limit];
void solve()
string str;
cin>>str;
n = str.length();
str = " " + str;
string num = " 314159265358979323846264338327";
rep(i,1,n)
int x = str[i] - \'0\';
if(str[i] != num[i])
cout<<i-1<<endl;
return;
cout<<n<<endl;
;
int32_t main()
#ifdef LOCAL
FOPEN;
// FOUT;
#endif
FASTIO
int kase;
cin>>kase;
while (kase--)
invoke(solve);
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s";
return 0;
B. Taisia and Dice
这个题题意是给出一个n个骰子的序列,然后我们知道筛子上面的总和是s,然后去掉最大的那个总和是r,要求给出一种序列构造。
这个题就是贪心,懒得讲了,直接看代码。
AC 代码
#include <bits/stdc++.h>
using namespace std;
constexpr int limit = (4e5 + 5);//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-9
#define FASTIO ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define pi(a, b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a ; --i)
#define MOD 998244353
#define traverse(u) for(int i = head[u]; ~i ; i = edge[i].next)
#define FOPEN freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
inline ll read()
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
ll sign = 1, x = 0;
char s = getchar();
while (s > \'9\' || s < \'0\')
if (s == \'-\')sign = -1;
s = getchar();
while (s >= \'0\' && s <= \'9\')
x = (x << 3) + (x << 1) + s - \'0\';
s = getchar();
return x * sign;
#undef getchar
//快读
void print(ll x)
if (x / 10) print(x / 10);
*O++ = x % 10 + \'0\';
void write(ll x, char c = \'t\')
if (x < 0)putchar(\'-\'), x = -x;
print(x);
if (!isalpha(c))*O++ = c;
fwrite(obuf, O - obuf, 1, stdout);
O = obuf;
int n,m;
int a[limit];
void solve()
int s,r;
cin>>n>>s>>r;
a[1] = s - r;//现在的
int rem = s - (n - 1) - a[1];
rep(i,2,n)
int minn = max(0, min(rem, a[1] - 1));
a[i] = 1 + minn;
rem -= minn;
per(i,1,n)
cout<<a[i]<<" ";
cout<<endl;
;
int32_t main()
#ifdef LOCAL
FOPEN;
// FOUT;
#endif
FASTIO
int kase;
cin>>kase;
while (kase--)
invoke(solve);
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s";
return 0;
C. Premutation
这题题意是,我们有个permutation,然后我们操作n次,第i次遮住第i个数字,然后所有操作序列给出,但是未必是按照顺序来的,要求我们复原这个permutation。
这个题看样例,我们发现第一列必然只有一个数字出现了1次,而且每一列有且只有两个数字,那么我们想一下就会发现两件事
- 第一列只出现一次的数字是permutation的第二个数字, 出现n-1次的数字是permutation的第一个数字
- 我们可以通过一列数字来推出当前和接下来一位总共两位数字
这个性质是有传递性的,也就是说我们可以通过前两列来推出第三列,第三列来推出第四列,以此类推。
接下来就很简单了,我手太生了,写锅了好几次,不过最后还是写出来了。
AC 代码
#include <bits/stdc++.h>
using namespace std;
constexpr int limit = (4e5 + 5);//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-9
#define FASTIO ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define pi(a, b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a ; --i)
#define MOD 998244353
#define traverse(u) for(int i = head[u]; ~i ; i = edge[i].next)
#define FOPEN freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
inline ll read()
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
ll sign = 1, x = 0;
char s = getchar();
while (s > \'9\' || s < \'0\')
if (s == \'-\')sign = -1;
s = getchar();
while (s >= \'0\' && s <= \'9\')
x = (x << 3) + (x << 1) + s - \'0\';
s = getchar();
return x * sign;
#undef getchar
//快读
void print(ll x)
if (x / 10) print(x / 10);
*O++ = x % 10 + \'0\';
void write(ll x, char c = \'t\')
if (x < 0)putchar(\'-\'), x = -x;
print(x);
if (!isalpha(c))*O++ = c;
fwrite(obuf, O - obuf, 1, stdout);
O = obuf;
int n,m;
int a[limit];
int mp[105][105];
void solve()
cin>>n;
rep(i,1,n)
rep(j, 1, n - 1)
cin>>mp[i][j];
set<int>s;
rep(i,1,n)
s.insert(i);
map<int, int>mpp;
rep(i,1,n)
mpp[mp[i][1]]++;
int now = -1;
int last;
for(auto [k, v]: mpp)
// cout<<k<<" "<<v<<endl;
if(v == 1)
now = k;
else
last = k;
a[1] = last;
s.extract(last);
int tot = 2;
int next = now;
rep(j,2,n - 1)
int res = 0;
rep(i,1,n)
if(mp[i][j] != next) //如果现在还不是下一个
res = mp[i][j];
else
a[tot] = mp[i][j];
s.extract(a[tot++]);
next = res;
if(s.size())
a[n] = *s.begin();
rep(i,1,n)
cout<<a[i]<<" ";
cout<<endl;
;
int32_t main()
#ifdef LOCAL
FOPEN;
// FOUT;
#endif
FASTIO
int kase;
cin>>kase;
while (kase--)
invoke(solve);
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s";
return 0;
D. Matryoshkas
这个题问你,给出n个数字,要求我们拆解成尽可能少的公差为1的等差数列,第一项随意,然后输出最少能拆成几个。
这个题首先暴力是没法划分的(显然)。我甚至想到了网络流,刚准备建图,但总觉得有更简单的做法。考虑一下之后,发现我们可以从出现次数最少的入手,那么我们每次连续删除以当前出现次数最少的数字为中心(其实这个说法不准确,应该是包含这个数字的连续序列),贪心地向两边扩展,直到遇到第一个没出现的数字为止。我们用map记录下数字的出现次数。最后操作总数一定是bound在O(N)的,复杂度也就是O(NlogN)了。
AC 代码
#include <bits/stdc++.h>
using namespace std;
constexpr int limit = (4e5 + 5);//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-9
#define FASTIO ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define pi(a, b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a ; --i)
#define MOD 998244353
#define traverse(u) for(int i = head[u]; ~i ; i = edge[i].next)
#define FOPEN freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
inline ll read()
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
ll sign = 1, x = 0;
char s = getchar();
while (s > \'9\' || s < \'0\')
if (s == \'-\')sign = -1;
s = getchar();
while (s >= \'0\' && s <= \'9\')
x = (x << 3) + (x << 1) + s - \'0\';
s = getchar();
return x * sign;
#undef getchar
//快读
void print(ll x)
if (x / 10) print(x / 10);
*O++ = x % 10 + \'0\';
void write(ll x, char c = \'t\')
if (x < 0)putchar(\'-\'), x = -x;
print(x);
if (!isalpha(c))*O++ = c;
fwrite(obuf, O - obuf, 1, stdout);
O = obuf;
int n,m;
int a[limit];
struct node
int val, cnt;
bool operator < (const node &rhs) const
return val < rhs.val;
;
void solve()
cin>>n;
rep(i,1,n)
cin>>a[i];
sort(a + 1, a + 1 + n);
int ans = 0;
map<int, int>mp;
for_each(a + 1, a + 1 + n, [&](int x)mp[x]++;);
vector<node>v;
for(auto [k, vv] : mp)
v.push_back(vv, k);
sort(v.begin(), v.end());
for(auto [cnt, num] : v)
rep(_, 1, cnt)
if(!mp[num])continue;
per(i,1,num)
if(!mp[i])
break;
mp[i]--;
rep(i, num + 1, 1e12)
if(!mp[i])
break;
mp[i]--;
++ans;
cout<<ans<<endl;
;
int32_t main()
#ifdef LOCAL
FOPEN;
// FOUT;
#endif
FASTIO
int kase;
cin>>kase;
while (kase--)
invoke(solve);
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s";
return 0;
E. Vlad and a Pair of Numbers
这个题是给出来a + b的和,要求找出来a和b使得
a \\oplus b = \\fraca + b2
如果不存在就输出1.
首先我们反向思维一下,这题的本质是a + b异或,然后右移一位。
首先我们可以确定,因为右移的关系,替换到左边就是左移,所以这个\\(a \\oplus b\\)的值一定是偶数。
然后我们考虑一下i和i - 1位置上之间的关系,如果\\(a \\oplus b\\)的值在第i位是1,那么只能说明一个问题,就是当前位置上是1和0(分别),那么如果这一位是这样,前一位的就不能是1,因为这样就会导致异或的结果是奇数,所以我们可以得到二个结论,就是如果\\(a \\oplus b\\)的值在第i位是1,那么第i - 1位a和b一定都是1,否则答案就不存在。
然后上代码
AC 代码
#include <bits/stdc++.h>
using namespace std;
constexpr int limit = (4e5 + 5);//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-9
#define FASTIO ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define pi(a, b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a ; --i)
#define MOD 998244353
#define traverse(u) for(int i = head[u]; ~i ; i = edge[i].next)
#define FOPEN freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
inline ll read()
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
ll sign = 1, x = 0;
char s = getchar();
while (s > \'9\' || s < \'0\')
if (s == \'-\')sign = -1;
s = getchar();
while (s >= \'0\' && s <= \'9\')
x = (x << 3) + (x << 1) + s - \'0\';
s = getchar();
return x * sign;
#undef getchar
//快读
void print(ll x)
if (x / 10) print(x / 10);
*O++ = x % 10 + \'0\';
void write(ll x, char c = \'t\')
if (x < 0)putchar(\'-\'), x = -x;
print(x);
if (!isalpha(c))*O++ = c;
fwrite(obuf, O - obuf, 1, stdout);
O = obuf;
int n,m;
int a[limit];
struct node
int val, cnt;
bool operator < (const node &rhs) const
return val < rhs.val;
;
void solve()
cin>>n;
rep(i,1,n)
cin>>a[i];
sort(a + 1, a + 1 + n);
int ans = 0;
map<int, int>mp;
for_each(a + 1, a + 1 + n, [&](int x)mp[x]++;);
vector<node>v;
for(auto [k, vv] : mp)
v.push_back(vv, k);
sort(v.begin(), v.end());
for(auto [cnt, num] : v)
rep(_, 1, cnt)
if(!mp[num])continue;
per(i,1,num)
if(!mp[i])
break;
mp[i]--;
rep(i, num + 1, 1e12)
if(!mp[i])
break;
mp[i]--;
++ans;
cout<<ans<<endl;
;
int32_t main()
#ifdef LOCAL
FOPEN;
// FOUT;
#endif
FASTIO
int kase;
cin>>kase;
while (kase--)
invoke(solve);
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s";
return 0;
F. Timofey and Black-White Tree
这题真不会,是vp结束之后看jiangly代码写的,这题本质是有根树,每次把节点涂黑,问黑节点当中距离最小的值是多少。
我之前想的是用lca,维护lca群,然后每次更新的时候分为两种情况,一种是lca在底下,那么记录一下lca下面离得最近的黑色节点,然后更新ans,另一种是lca在上面,那么就把lca的父亲节点的最近的黑色节点更新一下,然后更新ans,再把所有淘汰的节点从里面pop掉,重构lca群。
听上去很无敌,但是读了下题发现是有根树,那就不行了。
赛后看的是,应该是简单的bfs,用贪心去收集答案,在bfs的时候每次只有答案小于当前的最小值才更新,复杂度\\(O(n\\sqrt n)\\)
然后上代码
AC 代码
#include <bits/stdc++.h>
using namespace std;
constexpr int limit = (4e5 + 5);//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-9
#define FASTIO ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define pi(a, b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a ; --i)
#define MOD 998244353
#define traverse(u) for(int i = head[u]; ~i ; i = edge[i].next)
#define FOPEN freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
inline ll read()
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
ll sign = 1, x = 0;
char s = getchar();
while (s > \'9\' || s < \'0\')
if (s == \'-\')sign = -1;
s = getchar();
while (s >= \'0\' && s <= \'9\')
x = (x << 3) + (x << 1) + s - \'0\';
s = getchar();
return x * sign;
#undef getchar
//快读
void print(ll x)
if (x / 10) print(x / 10);
*O++ = x % 10 + \'0\';
void write(ll x, char c = \'t\')
if (x < 0)putchar(\'-\'), x = -x;
print(x);
if (!isalpha(c))*O++ = c;
fwrite(obuf, O - obuf, 1, stdout);
O = obuf;
int n,m;
int a[limit];
vector<int>g[limit];
int c[limit];
int fa[limit];
int find(int x)
return x == fa[x] ? x : fa[x] = find(fa[x]);
void merge(int x,int y)
int fx = find(x);
int fy = find(y);
if(fx != fy)
fa[fx] = fy;
int sizes[limit], pre[limit], son[limit], dep[limit], top[limit], dfn[limit], tot;
void dfs1(int u, int f, int d)
dep[u] = d;
sizes[u] = 1;
pre[u] = f;
for (auto v : g[u])
if (v == f)continue;
dfs1(v, u, d + 1);
sizes[u] += sizes[v];
if (sizes[v] > sizes[son[u]])son[u] = v;
void dfs2(int u, int t)
dfn[u] = ++tot;
top[u] = t;
if (son[u])dfs2(son[u], t);
for (auto v : g[u])
if (v == pre[u] || v == son[u])continue;
dfs2(v, v);
int lca(int x, int y)
while (top[x] != top[y])
if (dep[top[x]] < dep[top[y]])swap(x, y);
x = pre[top[x]];
return dep[x] < dep[y] ? x : y;
int dis(int x, int y)
return dep[x] + dep[y] - 2 * dep[lca(x, y)];
int dist[limit];
void solve()
cin>>n>>c[1];
rep(i,1,n)
g[i].clear();
fa[i] = i;\\
dist[i] = numeric_limits<int>::max();
rep(i,2,n)
cin>>c[i];
rep(i,1,n - 1)
int u,v;
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
int ans = INF;
auto bfs = [&](int x)
queue<int>q;
q.push(x);
dist[x] = 0;
while(!q.empty())
int u = q.front();
q.pop();
for(auto v : g[u])
if(dist[v] > dist[u] + 1 and dist[u] + 1 < ans )
dist[v] = dist[u] + 1;
q.push(v);
;
bfs(c[1]);
rep(i,2,n)
a[i] = ans = min(ans,dist[c[i]]);
bfs(c[i]);
rep(i,2,n)
cout<<a[i]<<\' \';
cout<<endl;
;
int32_t main()
#ifdef LOCAL
FOPEN;
// FOUT;
#endif
FASTIO
int kase;
cin>>kase;
while (kase--)
invoke(solve);
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s";
return 0;
G. Tokens on Graph
这个题是给了一些token和一个无向图,我们的任务是把一个token移动到编号为1的节点上去。然后有一些bonus节点,没有使用次数和流量限制,但是我们不能连续移动一个token,而且我们每次需要把节点上的token移动到bonus节点上去才能继续走下一次。问给出一个构造图,能不能在一轮游戏中把一个token移动到编号为1的节点上去。
我卡在F了一会儿,发现关注的人都去做G了,所以我也来看G。
这道题我们发现,首先需要有至少一个token,其通往节点1的路径最短,且途中必须全部由bonus节点组成。我们有若干个token,把这个token拿掉,继续看其他token,所以每个token可以移动1次或者无数次(因为没有使用次数限制,如果路上有两个bonus节点就back and forth就好了),如果不存在无数次的,那么我们看看选中最短路的费用 - 1是否可以由其他只能move一次的token抵消掉.如果可以,那么yes,否则no
然后wa了,发现我们在统计步长为1的链的时候,对答案贡献最多为一次,改了就过了
AC代码
#include <bits/stdc++.h>
using namespace std;
constexpr int limit = (4e5 + 5);//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-9
#define FASTIO ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define pi(a, b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a ; --i)
#define MOD 998244353
#define traverse(u) for(int i = head[u]; ~i ; i = edge[i].next)
#define FOPEN freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\\\Users\\\\tiany\\\\CLionProjects\\\\akioi\\\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
inline ll read()
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
ll sign = 1, x = 0;
char s = getchar();
while (s > \'9\' || s < \'0\')
if (s == \'-\')sign = -1;
s = getchar();
while (s >= \'0\' && s <= \'9\')
x = (x << 3) + (x << 1) + s - \'0\';
s = getchar();
return x * sign;
#undef getchar
//快读
void print(ll x)
if (x / 10) print(x / 10);
*O++ = x % 10 + \'0\';
void write(ll x, char c = \'t\')
if (x < 0)putchar(\'-\'), x = -x;
print(x);
if (!isalpha(c))*O++ = c;
fwrite(obuf, O - obuf, 1, stdout);
O = obuf;
int n,m;
int a[limit];
vector<int> g[limit], g2[limit];
int token[limit];
int bonus[limit];
int fa[limit];
int vis[limit];
int find(int x)
return fa[x] == x ? x : fa[x] = find(fa[x]);
void merge(int x,int y)
int fx = find(x);
int fy = find(y);
if(fx != fy)
if(fx > fy)swap(fx,fy);
fa[fx] = fy;
void solve()
int p, b;
cin>>n>>m;
cin>>p>>b;
rep(i,1,n)
fa[i] = i;
rep(i,1,p)
cin>>token[i];
rep(i,1,b)
cin>>bonus[i];
sort(token + 1,token + 1 + p);
sort(bonus + 1,bonus + 1 + b);
rep(i,1,n)
g[i].clear();
vis[i] = 0;
rep(i,1,m)
int u,v;
cin>>u>>v;
if(u != 1 and !binary_search(token + 1,token + 1 + p,u) and !binary_search(bonus + 1,bonus + 1 + b,u))
continue;
if(v != 1 and !binary_search(token + 1,token + 1 + p,v) and !binary_search(bonus + 1,bonus + 1 + b,v))
continue;
g[u].push_back(v);
g[v].push_back(u);
if(binary_search(token + 1,token + 1 + p,1))
cout<<"Yes"<<endl;
return;
auto [rt, cost] = [&]()->pi(int, int)
queue<pi(int, int)>q;
q.push(1, 0);
vis[1] = 1;
while(!q.empty())
auto [u, c] = q.front();
q.pop();
if(binary_search(token + 1,token + 1 + p,u))
return u, c;
for(auto v : g[u])
if(!vis[v])
vis[v] = 1;
q.push(v, c + 1);
return 0, 0;
();
// cout<<rt<<" "<<cost<<endl;
if(!rt)
cout<<"No"<<endl;
return;
int big = 0, small = 0;//分别代表反复横跳和直接跳到的次数
rep(i,1,p)
int res = 0;
if(token[i] == rt)continue;
queue<pi(int, int)>q;
q.push(token[i], 0);
while(q.size())
auto [u, c] = q.front();
q.pop();
if(c == 2)
res--;
big = 1;
break;
if(c == 1)
res++;
for(auto v : g[u])
if(binary_search(bonus + 1,bonus + 1 + b,v))
q.push(v, c + 1);
if(res > 0)
small++;
// cout<<big<<" "<<small<<endl;
if(big)
cout<<"Yes"<<endl;
return;
if(small >= cost - 1)
cout<<"Yes"<<endl;
return;
cout<<"No"<<endl;
;
int32_t main()
#ifdef LOCAL
FOPEN;
// FOUT;
#endif
FASTIO
int kase;
cin>>kase;
while (kase--)
invoke(solve);
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s";
return 0;
<\\details>
Codeforces Round #815 (Div. 2) 题解
以上是关于Codeforces 847 Div3 题解A-G的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #719 (Div. 3) A-G题解 G题详细注释
Codeforces Round #719 (Div. 3) A-G题解 G题详细注释
Codeforces Round #725 (Div. 3) 题解(A-G)