Codeforces Round #756 (Div. 3)

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

简单的一个分组问题,最多能分得的队伍由

  1. 总队伍数限制
  2. 最少队伍的人数限制

考虑到这两个限制之后,只需同时满足 队伍数量 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) nummin(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 满足一下几个性质:

  1. 数组中最大值一定会在 a a a 中的两端出现,因为最大的数只会在最后被拿下来。
  2. 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 n1 条边的树, 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();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值