A. Make Even
反转下标从 1 1 1 开始到 k k k 的值,分为一下几种情况
- 本来就是偶数,花费 0 0 0 次
- 第一位是偶数 反转整个, 花费 1 1 1 次
- 偶数字在中间, 先将偶数反转到第一位再反转到最后一位, 花费 2 2 2 次
- 没有偶数 输出 − 1 -1 −1
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
void solve() {
string s;
cin >> s;
if( (s[s.size() - 1] - '0') % 2 == 0) {
cout << 0 << '\n';
return;
}
if((s[0] - '0') % 2 == 0) {
cout << 1 << '\n';
return;
}
for(int i = 1; i < s.size(); i ++) {
if((s[i] - '0') % 2 == 0) {
cout << 2 <<'\n';
return;
}
}
cout << -1 << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("D:/Cpp/program/Test.in", "r", stdin);
freopen("D:/Cpp/program/Test.out", "w", stdout);
#endif
int t;
cin >> t;
while(t --) {
solve();
}
}
B. Team Composition: Programmers and Mathematicians
简单的一个分组问题,最多能分得的队伍由
- 总队伍数限制
- 最少队伍的人数限制
考虑到这两个限制之后,只需同时满足 队伍数量 n u m num num
- num <=
(
a
+
b
)
/
4
(a + b)/ 4
(a+b)/4 &&
n
u
m
≤
min
(
a
,
b
)
num \le \min(a, b)
num≤min(a,b)
即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("D:/Cpp/program/Test.in", "r", stdin);
freopen("D:/Cpp/program/Test.out", "w", stdout);
#endif
int t;
cin >> t;
while(t --) {
ll a, b;
cin >> a >> b;
ll temp = (a + b) / 4;
cout << min(min(a, b), temp) << '\n';
}
}
C. Polycarp Recovers the Permutation
题目中给的新数组 a a a 满足一下几个性质:
- 数组中最大值一定会在 a a a 中的两端出现,因为最大的数只会在最后被拿下来。
- a a a 中两端的数在原来的数组 p p p 中一定可以变为相邻的数,因为都是最后拿下来的。
有了以上两个性质,我们可以考虑一种构造,将去除了两端的数组 a a a 记录下来,并将他们反转 ( r e v e r s e ) (reverse) (reverse),然后全部放在最大值的左侧,这样他们就会因为小于最右侧的最大值,按顺序被从右侧放下来。然后两端的数按原来的顺序放在最后就好。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 2e5 + 10;
int a[N];
void solve() {
int n;
cin >> n;
int b[n];
for(int i = 1; i <= n; i ++) cin >> a[i];
if(a[1] != n && a[n] != n) {
cout << -1 << '\n';
return;
}
if(n == 1) {
cout << 1 << '\n';
return;
}
int m1 = a[1], m2 = a[n];
int cnt = 0;
for(int i = 2; i < n; i ++) {
b[++ cnt] = a[i];
}
reverse(b + 1, b + cnt + 1);
for(int i = 1; i <= cnt; i ++) cout << b[i] << ' ';
cout << m1 << ' ' << m2 << ' ';
cout << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("D:/Cpp/program/Test.in", "r", stdin);
freopen("D:/Cpp/program/Test.out", "w", stdout);
#endif
int t;
cin >> t;
while(t --) {
solve();
}
return 0;
}
D. Weights Assignment For Tree Edges
b
b
b 数组表示
i
i
i 的父节点为
b
[
i
]
b[i]
b[i],
p
p
p 数组表示
p
[
i
]
p[i]
p[i] 节点在树中距离根节点的距离的排名为
i
i
i
p
[
1
]
p[1]
p[1] 表示为根节点;
p
[
2
]
p[2]
p[2] 表示距离根节点最近的点…。现在要求构造出
d
i
s
t
dist
dist ,
d
i
s
t
[
i
]
dist[i]
dist[i] 表示 点
i
i
i 到父节点的距离。使得每个节点到根节点的距离的排名满足
p
[
i
]
p[i]
p[i]。如果不能构造出,输出
−
1
-1
−1
我们直接对
p
p
p 中的排列进行对边权的赋值,对第一个点赋值为 0,之后的点按照升序设置其到根节点的距离。如果当前设置的点的父节点没有被更新过,即父节点后于自己更新,就说明无法满足
p
p
p 的顺序。
那么,最后的答案就可以得到是:每个点到根节点的距离减去父节点到根节点的距离。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 2e5 + 10;
int p[N], fa[N], ans[N], dis[N];
int n;
void solve() {
cin >> n;
int root;
for(int i = 1; i <= n; i ++) {
cin >> fa[i];
if(fa[i] == i) root = i;
dis[i] = -1;
}
for(int i = 1; i <= n; i ++) cin >> p[i];
dis[root] = 0, ans[root] = 0;
if(root != p[1]) {
cout << -1 << '\n';
return;
}
for(int i = 2; i <= n; i ++) {
int j = p[i];
if(dis[fa[j]] == -1) {
cout << -1 << '\n';
return;
}
dis[j] = i;
ans[j] = dis[j] - dis[fa[j]];
}
for(int i = 1; i <= n; i ++) cout << ans[i] << ' ';
cout << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("D:/Cpp/program/Test.in", "r", stdin);
freopen("D:/Cpp/program/Test.out", "w", stdout);
#endif
int t;
cin >> t;
while(t --) solve();
return 0;
}
E1. Escape The Maze (easy version)
题目概述:
有一颗含
n
n
n 个节点,
n
−
1
n - 1
n−1 条边的树,
V
l
a
d
Vlad
Vlad 从根节点出发, 他的朋友在某些节点上。他和朋友们每次都可以同时移动一次。现在问
V
l
a
d
Vlad
Vlad 是否能在不与朋友们相遇的情况下到达叶子节点。
思路 :
设
d
e
e
p
[
i
]
deep[i]
deep[i] 表示 点
i
i
i 的深度(
d
e
e
p
[
1
]
=
1
deep[1] = 1
deep[1]=1),
f
[
i
]
f[i]
f[i] 表示 距离点
i
i
i 最近的一个朋友所在的深度。
要使得
V
l
a
d
Vlad
Vlad 不与朋友相遇,应满足:
对于
V
l
a
d
Vlad
Vlad 从根节点到叶子节点的路径上的任意一个点
u
u
u,满足
d
e
e
p
[
u
]
−
1
<
f
[
u
]
−
d
e
e
p
[
u
]
deep[u] - 1 < f[u] - deep[u]
deep[u]−1<f[u]−deep[u],并且,该点
u
u
u 一定是可以通往一个没有朋友在的叶子节点的。
具体代码实现如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 2e5 + 10, M = N * 2;
int n, m;
int e[M], ne[M], h[N], idx;
int deep[N], f[N];
bool is_friend[N], is_safe[N];
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
void dfs(int u, int fa) {
deep[u] = deep[fa] + 1;
if(is_friend[u]) {
f[u] = deep[u];
return;
}
bool safe = false;
//判断为叶子节点
if(ne[h[u]] == -1 && u != 1) safe = true;
for(int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if(j == fa) continue;
dfs(j, u);
if(is_safe[j]) safe = true; //存在通往叶子节点的路径
f[u] = min(f[u], f[j]);
}
if(safe && deep[u] - 1 < f[u] - deep[u]) is_safe[u] = true;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("D:/Cpp/program/Test.in", "r", stdin);
freopen("D:/Cpp/program/Test.out", "w", stdout);
#endif
int t;
cin >> t;
while(t --) {
idx = 0;
memset(h, -1, sizeof h);
memset(is_friend, 0, sizeof is_friend);
memset(is_safe, 0, sizeof is_safe);
memset(f, 0x3f, sizeof f);
cin >> n >> m;
for(int i = 1; i <= m; i ++) {
int friends;
cin >> friends;
is_friend[friends] = true;
}
for(int i = 1; i < n; i ++) {
int a, b;
cin >> a >> b;
add(a, b), add(b, a);
}
dfs(1, -1);
if(is_safe[1]) cout << "YES" << '\n';
else cout << "NO" << '\n';
}
}
E2. Escape The Maze (hard version)
题目概述:
在
E
1
E1
E1 的基础上,如果朋友能与
V
l
a
d
Vlad
Vlad 相遇, 问最少需要几个朋友就可以一定与
V
l
a
d
Vlad
Vlad 相遇。如果不能相遇输出
−
1
-1
−1。
思路:
显然,当所有点都在往上走时,会使一些朋友走到同一个位置上,对于一些可以拦截住
V
l
a
d
Vlad
Vlad 的位置,我们只需一个朋友即可。
所以我们从上向下再
d
f
s
(
)
dfs()
dfs() 一次,遇到第一个可以拦截的点,就使需要的朋友数量
a
n
s
ans
ans++
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 2e5 + 10, M = N * 2;
int e[M], ne[M], h[N], idx;
int deep[N], f[N];
bool is_friend[N], is_safe[N];
int ans;
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
void dfs(int u, int fa) {
deep[u] = deep[fa] + 1;
if(is_friend[u]) {
f[u] = deep[u];
return;
}
bool safe = false;
if(ne[h[u]] == -1 && u != 1) safe = true;
for(int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if(j == fa) continue;
dfs(j, u);
f[u] = min(f[u], f[j]);
if(is_safe[j]) safe = true;
}
if(safe && deep[u] - 1 < f[u] - deep[u]) is_safe[u] = true;
}
void dfs1(int u, int fa) {
if(deep[u] - 1 >= f[u] - deep[u]) {
//cout << "u == " << u << '\n';
ans ++;
return;
}
for(int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if(j == fa) continue;
dfs1(j, u);
}
}
void solve() {
idx = 0;
memset(h, -1, sizeof h);
memset(f, 0x3f, sizeof f);
memset(is_safe, 0, sizeof is_safe);
memset(is_friend, 0, sizeof is_friend);
int n, m;
cin >> n >> m;
while(m --) {
int x;
cin >> x;
is_friend[x] = true;
}
for(int i = 1; i < n; i ++) {
int a, b;
cin >> a >> b;
add(a, b), add(b, a);
}
dfs(1, 0);
if(is_safe[1]) cout << -1 << '\n';
else {
ans = 0;
dfs1(1, -1);
cout << ans << '\n';
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("D:/Cpp/program/Test.in", "r", stdin);
freopen("D:/Cpp/program/Test.out", "w", stdout);
#endif
int t;
cin >> t;
while(t --) {
solve();
}
}