Codeforces Round 886 (Div. 4) 题解 A - H

发布时间 2023-07-23 22:27:07作者: 叁纔

A. To My Critics

题目大意

给定三个数,你可以挑俩数加起来,问这仨数有没有可能加起来大于等于 \(10\) .

解题思路

我们找其中最大的两个数相加与 \(10\) 比较即可。

AC Code

#include <iostream>
#include <algorithm>
#include <cstring>
#define endl '\n'
#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
using namespace std;
typedef long long LL;

const int N = 4e5 + 10;
const int MOD = 1e9 + 7;

int a[3];

void solve() {
    for (int & i : a) {
        cin >> i;
    }
    sort(a, a + 3);
    cout << (a[1] + a[2] >= 10 ? "YES" : "NO") << endl;
}

signed main() {
    ios;
    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
}

B. Ten Words of Wisdom

题目大意

每次给定两个数,要找满足第一个数小于等于10的情况下第二个数的最大值。

解题思路

我们可以读入时直接扔掉第一个数大于10的,其余只存储第二个数,再按照从大到小排序找第一个元素即可。

AC Code

#include <iostream>
#include <algorithm>
#include <cstring>
#define endl '\n'
#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
using namespace std;
typedef long long LL;

const int N = 4e5 + 10;
const int MOD = 1e9 + 7;


void solve() {
    int n;
    cin >> n;
    vector<pair<int, int>> v(n + 1);
    for (int i = 1; i <= n; ++i) {
        int a, b;
        cin >> a >> b;
        if (a <= 10) {
            v.emplace_back(b, i);
        }
    }
    sort(v.begin(), v.end(), greater<>());
    cout << v.begin()->second << endl;
}

signed main() {
    ios;
    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
}

C. Word on the Paper

题目大意

给定一堆字符串,点表示空白,字符串图中有竖着写的单词,现在我们需要找到这个单词。

解题思路

不管他是怎么排列的,我们输出的就是这张字符串图中的非点字符,那么我们把除了点以外读到的字符按序输出即可。

AC Code

#include <iostream>
#include <algorithm>
#include <cstring>
#define endl '\n'
#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
using namespace std;
typedef long long LL;

const int N = 4e5 + 10;
const int MOD = 1e9 + 7;


void solve() {
    char c;
    for (int i = 1; i <= 8; ++i) {
        for (int j = 1; j <= 8; ++j) {
            cin >> c;
            if (c != '.') cout << c;
        }
    }
    cout << endl;
}

signed main() {
    ios;
    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
}

D. Balanced Round

题目大意

给定一串序列,我们可以对他进行删除操作,然后任意方式排列,使得最后得到的序列,满足相邻两项之差不大于 \(k\). 问需要删除多少元素。

解题思路

为了使得最终相邻两项之差的最大值尽可能小,那么我们可以先对序列排序。随后遍历,问题即转化为排序后的序列临差值不大于 \(k\) 的最长连续子序列长度。最终删去元素就是总长减去这个值。

AC Code

#include <iostream>
#include <algorithm>
#include <cstring>
#define endl '\n'
#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
using namespace std;
typedef long long LL;

const int N = 4e5 + 10;
const int MOD = 1e9 + 7;

int a[N];

void solve() {
    int n, k;
    cin >> n >> k;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
    }
    sort(a + 1, a + n + 1);
    LL cnt = 1, res = 1;
    for (int i = 2; i <= n; ++i) {
        if (a[i] - a[i - 1] <= k) {
            cnt++;
        } else {
            cnt = 1;
        }
        res = max(res, cnt);
    }
    cout << n - res << endl;
}

signed main() {
    ios;
    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
}

E. Cardboard for Pictures

题目大意

给定用掉的总共的纸板面积和每张图片的尺寸,问留白长度为多少。

解题思路

长度越大我们要花费的纸板就一定越多,那么我们可以使用二分答案的方式,check中计算对这样的留白长度需要多少纸板并和 \(c\) 比较即可。

AC Code

#include <iostream>
#include <algorithm>
#include <cstring>
#define endl '\n'
#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
using namespace std;
typedef long long LL;

const int N = 4e5 + 10;
const int MOD = 1e9 + 7;

int a[N];
LL n, c;

bool check(LL x) {
    LL res = 0;
    for (int i = 1; i <= n; ++i) {
        res += (a[i] + (x << 1)) * (a[i] + (x << 1));
        if (res > c) return false;
    }
    return res <= c;
}

void solve() {
    cin >> n >> c;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
    }
    LL l = 0, r = MOD;
    while (l < r) {
        LL mid = (l + r + 1) >> 1;
        if (check(mid)) {
            l = mid;
        } else {
            r = mid - 1;
        }
    }
    cout << l << endl;
}

signed main() {
    ios;
    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
}

F. We Were Both Children

题目大意

不太会化简题意,就给出翻译吧。

\(\text{Mihai}\)\(\text{Slavic}\) 正在观察一组从\(1\)\(n\)编号为\(n\)的青蛙,它们最初都位于\(0\)点。青蛙\(i\)的跳跃长度为 \(a_i\)

每秒钟,青蛙 \(i\) 向前跳跃 \(a_i\)个单位。在任何青蛙开始跳跃之前,\(\text{Slavic}\)\(\text{Mihai}\) 可以在一个坐标上放置一个捕捉器,以便捕捉所有经过相应坐标的青蛙。

但是,孩子们不能离家太远,所以他们只能在前\(n\)个点(即坐标在\(1\)\(n\)之间的点)放置一个陷阱,而且孩子们不能在\(0\)点放置陷阱,因为他们害怕青蛙。

您能帮助 \(\text{Slavic}\)\(\text{Mihai}\) 找出使用陷阱最多能捕捉多少只青蛙吗?

解题思路

模拟题述的过程,使用计数数组来记录每个点上有多少青蛙,为了便于存储,忽略掉所有超过范围的点,随后两重循环求解最大值即可。

AC Code

#include <iostream>
#include <algorithm>
#include <cstring>
#define endl '\n'
#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
using namespace std;
typedef long long LL;

const int N = 4e5 + 10;
const int MOD = 1e9 + 7;

int a[N];
int cnt[N], res[N];

void solve() {
    memset(res, 0, sizeof res);
    memset(cnt, 0, sizeof cnt);
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
        if (a[i] > n) a[i] = 0;
        cnt[a[i]]++;
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; i * j <= n; ++j) {
            res[i * j] += cnt[i];
        }
    }
    cout << *max_element(res + 1, res + n + 1) << endl;
}

signed main() {
    ios;
    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
}

G. The Morning Star

题目大意

指南针指向晨星,但是只能指向八个方向,否则他就会坏掉。现在给定一些点,你可以选择把指南针和晨星放在其中两个点,问有多少种组合可以使得指南针不会坏掉。

解题思路

我们注意到如果一种组合使得指南针不会坏掉那么调换指南针和晨星的位置也不会坏掉,所以我们只需要处理一半情况。

用四个数组记录这四个方向,对于一个坐标为 \((a,b)\) 的点来说,正上 \((a)\),正右 \((b)\),右上 \((a + b)\),左上 \((a - b)\) 四个方向不会使得指南针坏掉,那么我们只需要同时统计与更新这四个数组,最后答案翻倍即可。

AC Code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <map>
#define endl '\n'
#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
using namespace std;
typedef long long LL;

const int N = 4e5 + 10;
const int MOD = 1e9 + 7;

map<int, int> m1, m2, m3, m4;

void solve() {
    int n;
    m1.clear(), m2.clear(), m3.clear(), m4.clear();
    LL res = 0;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        int a, b;
        cin >> a >> b;
        res += m1[a]++;
        res += m2[b]++;
        res += m3[a + b]++;
        res += m4[a - b]++;
    }
    cout << (res << 1) << endl;
}

signed main() {
    ios;
    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
}

H. The Third Letter

题目大意

需要把士兵安排到营地里,每个整数点都有一个营地。我们需要按照某种特定的策略分配。给定策略中的 \(m\) 条限制条件,条件\(i\)告诉士兵\(a_i\)应该属于位于士兵\(b_i\)所属阵营前方\(d_i\)米处的阵营。(如果是\(d_i < 0\),那么\(a_i\)的营地应该在\(b_i\)的营地后面\(-d_i\)米处)。

我们需要判断这些条件是否可以同时满足。

解题思路

可以使用带权并查集解决这个问题,读取到一条条件就合并这两个点同时处理他们的权值,最后判断是否冲突即可。

AC Code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <map>
#define endl '\n'
#define ios ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
using namespace std;
typedef long long LL;

const int N = 4e5 + 10;
const int MOD = 1e9 + 7;

LL p[N], d[N];

LL find(LL x) {
    if (x != p[x]) {
        int tmp = find(p[x]);
        d[x] += d[p[x]];
        p[x] = tmp;
        return p[x];
    }
    return x;
}

void solve() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        p[i] = i;
        d[i] = 0;
    }
    bool flag = true;
    for (int i = 1; i <= m; ++i) {
        int a, b, dd;
        cin >> a >> b >> dd;
        LL ta = find(a);
        LL tb = find(b);
        if (ta != tb) {
            p[ta] = tb;
            d[ta] = d[b] - d[a] + dd;
        } else if (flag && d[a] - dd != d[b]) {
            flag = false;
            cout << "NO" << endl;
        }
    }
    if (flag) cout << "YES" << endl;
}

signed main() {
    ios;
    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
}