Codeforces Round #704 (Div. 2)【A ~ D题解】

A. Three swimmers

解题方法:我们可以发现,每个运动员的周期分别是a,b,c。于是我们的任务变成了找出p所在的周期位置,然后找到右边界到p的距离,对每个运动员到p的距离取最小值即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

inline void solve() {
    LL p, a, b, c; cin >> p >> a >> b >> c;
    LL k, res; // k存周期位置,res存答案
    k = (p + a - 1) / a; // 这里相当于 p / a向上取整,算出p所在a运动员的周期位置
    res = k * a - p;
    k = (p + b - 1) / b;
    res = min(res, k * b - p);
    k = (p + c - 1) / c;
    res = min(res, k * c - p);
    cout << res << endl;
}
int main() {
    int t; cin >> t;
    while (t -- ) solve();
    return 0;
}

B. Card Deck

解题思路:我们通过对样例分析后可以发现,我们可以模拟这样一个过程来达到目的
对这个数组从后往前遍历,每次遍历到当前剩余的最大值就取出来,然后接着往下取,取完为止
于是代码也显而易见了。因为数组是关于n的一个排列,所以这里我们用一个辅助数组st来存当前有哪些数字我们已经取出来了。

#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int n;
int p[N];
bool st[N]; // st[i] == true表示我们已经取出了i
inline void solve() {
    memset(st, false, sizeof st); // 别忘了初始化
    cin >> n;
    for (int i = 1; i <= n; i ++ ) cin >> p[i];
    int target = n; // 表示我们每次要找的数
    int last = n; // 表示我们上次找到的位置
    for (int i = n; i; i -- ) {
        if (p[i] == target) { // 找到了我们要找的数字
            for (int j = i; j <= last; j ++ ) cout << p[j] << ' '; // 输出到之前我们找到的数字为止
            last = i - 1;
            st[p[i]] = true;
            while (st[target]) target -- ; // 重新寻找剩余中的最大值
        } else st[p[i]] = true;
    }
    cout << endl;
}
int main() {
    int t; cin >> t;
    while (t -- ) solve();
    return 0;
}

C. Maximum width

解题思路:相当于我们要给字符串t找到在字符串s中一一对应的位置,然后求两个位置的最大值是多少。
我们通过对样例的简单分析和手动模拟后可以发现,通过贪心的方法,对于字符串t中的每个字符,在s中都有一个或者多个对应的位置,我们找到这个范围,存下来,然后答案显而易见就是每个字符的右边界到前一个字符的左边界的距离的最大值了。
于是问题就变成了如何求t中每个字符的边界,如果一下求好会比较难,但是可以分开求,一次求左边界,一次求右边界
我们用pair来存左右边界,或者用两个数组也可以

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
char s[200020], t[200020];
PII p[200020]; // first表示左边界,second表示右边界
int main() {
    int n, m; cin >> n >> m;
    scanf("%s%s", s + 1, t + 1);
    int l = 1, r = 1;
    //先计算左边界
    while (l <= n && r <= m) {
        if (s[l] == t[r]) {
            p[r].first = l;
            l ++ , r ++ ;
        } else l ++ ;
    }
    //再计算右边界
    l = n, r = m;
    while (l && r) {
        if (s[l] == t[r]) {
            p[r].second = l;
            l -- , r -- ;
        } else l -- ;
    }
    int res = 0;
    for (int i = 2; i <= m; i ++ ) res = max(res, p[i].second - p[i - 1].first);
    cout << res << endl;
    return 0;
}

D. Genius's Gambit

解题思路:构造题,真恶心好玩(主要是这题的特判搞得我比较难受)
这里介绍官方题解的思路其实就是本蒟蒻没写出来
先介绍构造方法,一般情况下,我们分为2种情况

第一种:a ≥ k

我们先让x为11...1100...00这样用b个1和a个0组成的2进制数,然后通过对x移位来构造y。
可以看出,我们将x中最后一个1向后移动k个位置,就凑出k个1来了。
如果看不出来,就自己多多构造几个数据,自己算算就理解了

第二种:a < k

我们可以看的出来,如果只用第一种的方法,还不够凑出k个1
我们就把y中的前面连续1中的最后一个向后移动一位,这样可以凑出一个1,如果不够就继续移动

于是我们这样就凑出来了答案
通过以上的构造方法,我们可以看出,k ≤ a + b - 2。
当然还有其他特判,对于5 10 0或者0 1 0这样的数据,我们可以看出,当k为0的时候,一定是存在答案的,怎么构造应该都会了
当然如果k不为0,那么当(a == 0 or b == 1)时候就构造不出来了(自己举一些例子就知道了)

#include <bits/stdc++.h>
using namespace std;

inline void solve() {
    int a, b, k; cin >> a >> b >> k;
    if (k == 0) { // 特判1
        puts("Yes");
        for (int i = 1; i <= b; i ++ ) cout << 1;
        for (int i = 1; i <= a; i ++ ) cout << 0;
        cout << endl;
        for (int i = 1; i <= b; i ++ ) cout << 1;
        for (int i = 1; i <= a; i ++ ) cout << 0;
    } else if (a + b - 2 < k) puts("No"); // 特判2
    else {
        if (a == 0 || b == 1) { // 特判3
            puts("No");
            return ;
        }
        // 构造
        puts("Yes");
        for (int i = 1; i <= b; i ++ ) cout << 1;
        for (int i = 1; i <= a; i ++ ) cout << 0;
        cout << endl;
        if (a >= k) {
            for (int i = 1; i < b; i ++ ) cout << 1;
            for (int i = 1; i <= k; i ++ ) cout << 0;
            cout << 1;
            for (int i = 1; i <= a - k; i ++ ) cout << 0;
            cout << endl;
        } else {
            int res = k - a;
            for (int i = 1; i < b - res; i ++ ) cout << 1;
            cout << 0;
            for (int i = 1; i <= res; i ++ ) cout << 1;
            for (int i = 1; i < a; i ++ ) cout << 0;
            cout << 1 << endl;
        }
    }
}
int main() {
//    int t; cin >> t;
//    while (t -- )
    solve();
    return 0;
}

E. Almost Fault-Tolerant Database

如果我会我就更新(估计不太可能了)

posted @ 2021-02-24 02:41  Time_Limit_Exceeded  阅读(44)  评论(0编辑  收藏  举报