Educational Codeforces Round 153 (Rated for Div. 2) A-C题解

A. Not a Substring

题解

对于这个题,我们可以考虑两种可能的连续的子串:

  • 有两个及以上的相同的字符,比如(((())),那么我们就需要尽可能地构造出连续不相同的字符串,比如()()()就非常符合我们的要求,每一对都不一样。

  • 有两个及以上的不相同的字符,比如)()(,那么我们就可以按照上面的想法,尽可能地构造出连续相同的字符串,那么((((()))))就是满足条件的最佳的字符串,因为它只有一对不相同的字符,而这一对是必须需要的。

所以呢,对于每个长度为n的串s,我们只需要构造出长度为2n的类似()()的串和类似(())的串,然后判断s是不是它们的子串,判断的方法就是使用cpp的string的find()函数查找

代码实现

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define SZ(x) (int)(x.size())
#define FOR(i,x,y) for (int i = (x),_##i = (y);i < _##i;i++)
#define FORD(i,x,y) for (int i = (x),_##i = (y);i > _##i;i--)
inline void solve();
int main() {
    ios::sync_with_stdio(false);cin.tie(nullptr);
    int t = 1;
    cin >> t;
    FOR (id, 1, t + 1) {solve();}
    return 0;
}
inline void solve() {
    string s, s1 = "", s2 = "";
    cin >> s;
    int n = SZ(s);
    FOR (i, 0, n) { // i 从 0 到 n - 1
        // 构造出类似()()的字符串s1
        s1 += "()";
    }
    FOR (i, 0, 2 * n) { // i 从 0 到 2 * n - 1,
        // 构造出类似(())的字符串s2
        if (i < n) {
            s2 += "(";
        } else {
            s2 += ")";
        }
    }
    if (s1.find(s) == s1.npos) {    // 如果s不是s1的子串
        cout << "YES\n";
        cout << s1 << "\n";
    } else if (s2.find(s) == s2.npos) { // 如果s不是s2的子串
        cout << "YES\n";
        cout << s2 << "\n";
    } else {    // 否则就是不存在了
        cout << "NO\n";
    }
}

B. Fancy Coins

题解

由于我们想尽可能地减少fancy coins的个数,所以需要多拿价值为k的硬币。但是价值为1的硬币会影响我们的判断,所以我们可以先只拿必要的价值为1的硬币,必要是因为m可能不是k的倍数。我们想一直拿价值为k的硬币就必须让m % k == 0,所以必要的价值为1的硬币个数cnt = m % k,剩余的价值为1的硬币a1-cnt可以将它们按k进行分组,变成价值为k的硬币。

然后我们考虑计算cnt时产生的fancy coins的个数,如果a1 >= cnt,那么fancy coins的个数就是0,否则就是cnt - a1

接下来考虑剩下的m,就是原始的m减去必要的价值为1的硬币cnt后的m,此时m % k == 0。这样我们只需要一直拿价值为k的硬币(包括剩下的价值为1的硬币a1-cnt组成的价值为k的硬币),那么很好想的就是先减去价值为k的regular coins,再减去价值为k的fancy coins。

代码

#include <cassert>
#include <iostream>
using namespace std;
using ll = long long;
#define FOR(i,x,y) for (int i = (x),_##i = (y);i < _##i;i++)
inline void solve();
int main() {
    ios::sync_with_stdio(false);cin.tie(nullptr);
    int t = 1;
    cin >> t;
    FOR (id, 1, t + 1) {solve();}
    return 0;
}
inline void solve() {
    ll m, k, a1, ak, ans = 0;   // ans记录fancy coins的总数
    cin >> m >> k >> a1 >> ak;

    if (m % k != 0) {
        ll cnt = m % k; // 必要的价值为1的硬币
        m -= cnt;
        if (a1 >= cnt) {    // 不需要使用价值为1的fancy coins
            a1 -= cnt;
        } else {    // 需要使用价值为1的fancy coins
            ans += cnt - a1;
            a1 = 0;
        }
    }
    assert(m % k == 0);

    m -= (a1 / k) * k;  // 价值为1的硬币组成的价值为k的硬币
    m -= ak * k;    // 价值为k的regular coins

    if (m < 0) {    // 不需要再使用价值为k的fancy coins
        cout << ans << "\n";
    } else {    // 还需要使用价值为k的fancy coins
        cout << ans + m / k << "\n";
    }
}

C. Game on Permutation

题解

从0到n-1

  • 对第一个lucky位置i来说,p[i]只需要比0 -> i - 1中的最小值大即可。比如说[3, 1, 2]中值为2的位置就是lucky的。

  • 对第二个及以上的lucky位置i来说,p[i]需要比0 -> i - 1中的最小值大,还需要比0 -> i - 1的所有lucky位置对应的值小。比如说[2, 1, 4, 3]中,4所在的位置是第一个lucky的,3所在的位置是第二个lucky的,因为3 > 1 && 3 < 4。再比如说[2, 1, 3, 4]中,3所在位置是第一个lucky的,而4所在的位置不是lucky的,因为4 > 3,导致从4所在的位置可以到达3所在的位置。

代码

#include <iostream>
using namespace std;
using ll = long long;
#define FOR(i,x,y) for (int i = (x),_##i = (y);i < _##i;i++)
inline void solve();
int main() {
    ios::sync_with_stdio(false);cin.tie(nullptr);
    int t = 1;
    cin >> t;
    FOR (id, 1, t + 1) {solve();}
    return 0;
}
inline void solve() {
    int n, ans = 0; // ans 记录答案个数
    cin >> n;
    int min_lucky_value = 1e9 , min_value = 1e9;    // 确保第一个lucky位置可以小于min_lucky_value
    FOR(i , 0, n) { // 0 -> n - 1
        int x;
        cin >> x;
        if (x > min_value && x < min_lucky_value) {
            ans++;
            min_lucky_value = x;    // x < min_lucky_value, 更新最小的lucky_value
        }
        min_value = min(min_value, x);  // 保证min_value 是0 -> i - 1的最小值
    }
    cout << ans << "\n";
}
posted @ 2023-08-21 01:03  Sleeping_Knight  阅读(17)  评论(0编辑  收藏  举报