Codeforces Round 656 (Div. 3)

Codeforces Round 656 (Div. 3) EFG

E

题意:给有向边和无向边,确定无向边的方向使得没有环。

如果有向图有环,那么无解决

如果无环,显然可以拓扑排序,然后让无向边,指向拓扑序靠后的就永远不会有环。

代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

#include <bits/stdc++.h>
#include <set>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
#define mk make_pair
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
int read()
{
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + c - '0', c = getchar();
return x * f;
}
vector<pii> ans;
vector<pii> g[N];
int n, m;
int vis[N], in[N], v[N];
bool solve()
{
queue<int> q;

for (int i = 1; i <= n; i++)
{
if (!in[i])
q.push(i);
}

while (!q.empty())
{
int x = q.front();
q.pop();
vis[x] = 1;
for (pii now : g[x])
{
int to = now.first;
if (now.second == 0)
{
in[to]--;
ans.push_back(mk(x, to));
if (!in[to])
q.push(to);
}
else if (!v[now.second])
{
v[now.second] = 1;
if (!vis[to])
ans.push_back(mk(x, to));
else
ans.push_back(mk(to, x));
}
}
}
for (int i = 1; i <= n; i++)
if (!vis[i])
return false;
return true;
}

int main()
{
int T = read();
while (T--)
{
n = read(), m = read();
for (int i = 1; i <= m; i++)
v[i] = 0;
for (int i = 1; i <= n; i++)
vis[i] = 0, in[i] = 0, g[i].clear();
ans.clear();
for (int i = 1; i <= m; i++)
{
int t = read(), x = read(), y = read();
if (t)
g[x].push_back(mk(y, 0)), in[y]++;
else
g[x].push_back(mk(y, i)), g[y].push_back(mk(x, i));
}
if (!solve())
{
puts("NO");
}
else
{
puts("YES");
for (pii now : ans)
{
printf("%d %d\n", now.first, now.second);
}
}
}
}

F

题意:每次删除正好$k$个同根的点和边。

队列模拟一下,注意要为被删掉为$k$的倍数才能算一次操作。

代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <bits/stdc++.h>
#include <set>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
#define mk make_pair
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
int read()
{
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + c - '0', c = getchar();
return x * f;
}

vector<int> g[N];
int d[N], p[N], vis[N];

int main()
{
int T = read();
while (T--)
{
int n = read(), k = read();
for (int i = 1; i <= n; i++)
g[i].clear(), d[i] = 0, p[i] = 0, vis[i] = 0;
for (int i = 1; i < n; i++)
{
int u = read(), v = read();
d[v]++;
d[u]++;
g[u].push_back(v);
g[v].push_back(u);
}
queue<int> q;
for (int i = 1; i <= n; i++)
if (d[i] == 1)
q.push(i);
int ans = 0;
while (!q.empty())
{
int x = q.front();
q.pop();
vis[x] = 1;
for (int to : g[x])
{
if (vis[to] == 1)
continue;
p[to]++;
d[to]--;
if (p[to] % k == 0)
{
ans++;
if (d[to] == 1)
q.push(to);
}
}
}
printf("%d\n", ans);
}
}

G

题意:两个数列,可以交换对应的坐标一次,就使得两个都是$1…n$的排序。

显然每个数出现2次即可,能保证完成。又可以找到,某些数字可以独立成环,枚举环$size$,和相应需要的翻转的次数$cnt$。显然假设再翻转一次,也可以。比较下$size-cnt,cnt$即可。

代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96


#include <bits/stdc++.h>
#include <set>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
#define mk make_pair
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
int read()
{
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + c - '0', c = getchar();
return x * f;
}

vector<int> g[N];
int vis[N];

int a[2][N];
int main()
{
int T = read();
while (T--)
{
int n = read();
for (int i = 1; i <= n; i++)
g[i].clear(), vis[i] = 0;
for (int i = 1; i <= n; i++)
a[0][i] = read(), g[a[0][i]].push_back(i);
for (int i = 1; i <= n; i++)
a[1][i] = read(), g[a[1][i]].push_back(i);
bool flag = 1;
for (int i = 1; i <= n; i++)
if (g[i].size() != 2)
flag = 0;
if (flag)
{
vector<int> ans;
for (int i = 1; i <= n; i++)
if (!vis[i])
{
if (a[0][i] == a[1][i])
continue;

int f = 0;
int x = a[0][i];
int p = i;
vector<pii> tmp;

int num = 0;
while (!vis[p])
{
vis[p] = 1;

int q = (g[x][0] == p ? g[x][1] : g[x][0]);

if (a[f][q] == x)
{
x = a[f ^ 1][q];
tmp.push_back(mk(q, 1));

num++;
}
else
{
x = a[f][q];
tmp.push_back(mk(q, 0));
}
p = q;
}

for (pii now : tmp)
{
if (now.second == (num <= tmp.size() - num))
ans.push_back(now.first);
}
}
printf("%d\n", ans.size());
for (int x : ans)
printf("%d ", x);
printf("\n");
}
else
puts("-1");
}
}