跳转至

2025年2月19日

Educational Codeforces Round 174 (Rated for Div. 2)

比赛链接:https://codeforces.com/contest/2069

这场感觉算正常发挥吧。D题1800人AC,我做不出来倒是正常。

至于这B和C,过的人都不少,写出来的速度有点慢了。这个C我怎么想得有点烧脑。。。然后瞎搞对了。

B写得也有点烂。

A

\(b_i\)\(1\) 时,\(b_{i-1}=b_i=b_{i+1}\) ,只有出现 \(101\) 时会有冲突,其他的都可以成立。

void solve()
{
    int n;
    cin>>n;
    vi a(n+1);
    for(int i=2;i<n;i++)
        cin>>a[i];
    for(int i=3;i+1<=n-1;i++){
        if(a[i-1]==1&&a[i+1]==1&&a[i]==0){
            cout<<"NO\n";
            return;
        }
    }
    cout<<"YES\n";
}

B

本来感觉这题可能也不好做的。。

每次需要选1种颜色,且不能有相邻的,那么每种颜色需要几次操作呢?我们有必要DFS吗?没有。其实一种颜色,操作次数只会是1次或者2次。

直接枚举就行了,如果一种颜色,它有相邻的块,那么需要两次操作,否则都是1次操作。

void solve()
{
    int n, m;
    cin >> n >> m;
    vector<vi> a(n + 1, vi(m + 1));
    vi cnt(n * m + 1);
    set<int> st;
    int mx = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) {
            cin >> a[i][j];
            cnt[a[i][j]]++;
            cmax(mx, cnt[a[i][j]]);
            st.insert(a[i][j]);
        }
    vector<bool> ok(n * m + 1);
    auto check = [&](int x, int y) {
        vector<pii> dirs { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 } };
        for (auto [xx, yy] : dirs) {
            int nx = xx + x, ny = yy + y;
            if (nx < 1 || nx > n || ny < 1 || ny > m)
                continue;
            if (a[nx][ny] == a[x][y])
                return true;
        }
        return false;
    };
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (check(i, j))
                ok[a[i][j]] = true;
        }
    }
    int ans = 0;
    for (auto x : st)
        ans += (ok[x] ? 2 : 1);
    if (ans != sz(st))
        ans -= 2;
    else
        ans -= 1;
    cout << ans << '\n';
}

C

首先一定要知道哪些情况是符合的,才好思考。。

我本来以为是只有 123 是可以的,,然后测了样例发现不对,它其实还有解释。那我们发现只需要首尾是1和3,中间2的数量无所谓。。那么就有点不好写。。

但是考虑DP就发现很简单,设\(dp_{0/1}\) 代表以 \(1\)\(2\) 结尾的合法子序列的数量。那么只有遇到 \(3\) 时,答案就可以加上 \(dp_{i-1}\)

如果 \(a_i\)\(1\) ,那么显然 \(dp_{i,0}=dp_{i-1}+1\) ,如果 \(a_i\)\(2\) , \(dp_{i,1}=2dp_{i-1,1}+dp_{i-1,0}\)

void solve()
{
    int n;
    cin >> n;
    vi a(n + 1);
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    vector<vl> dp(n + 1, vl(3));
    ll ans = 0;
    for (int i = 1; i <= n; i++) {
        dp[i] = dp[i - 1];
        if (a[i] == 1)
            dp[i][0]++;
        else if (a[i] == 2) {
            dp[i][1] = (dp[i][1] + dp[i - 1][0] + dp[i][1]) % mod;
        } else
            ans += dp[i][1], ans %= mod;
        // if (a[i] == 3)
        // cerr << dp[i][0] << " " << dp[i][1] << '\n';
    }
    cout << ans << '\n';
}

这里好唐,想了很久才想明白。。。

然后就战斗结束了。D感觉确实很难不看题解写出来。

D

use binary search ,如果当前字符串首尾相同,那显然我们不需要进行任何操作。所以我们可以先把字符串转换成首尾不同的状态,然后我们二分检查的长度。由于首尾不同,那么肯定要么是从开头开始,要么是在末尾结束。

对于在末尾结束的情况,我们可以用反转后的字符串来计算,所以我们只用考虑第一种情况。用前缀和存一下,就可以检查是否能构成回文串了。

void solve()
{
    string s;
    cin >> s;
    int n = sz(s);
    for (int i = 0; i < n - i - 1; i++) {
        if (s[i] != s[n - i - 1]) {
            s = s.substr(i, n - i - 1 - i + 1);
            break;
        }
    }
    if (sz(s) == n && s.front() == s.back()) {
        cout << "0\n";
        return;
    }
    cerr << s << "\n";
    n = sz(s);
    s = " " + s;

    vector<vi> pre(n + 1, vi(26));
    auto check = [&](int len) {
        if (len < n / 2) {
            for (int i = len + 1; i <= n / 2; i++) {
                if (s[i] != s[n - i + 1])
                    return false;
            }
        }
        for (int i = 0; i < 26; i++) {
            if (len >= n / 2) {
                if (pre[len][i] < pre[n][i] - pre[len][i])
                    return false;
            } else {
                if (pre[len][i] > pre[n][i] - pre[len][i])
                    return false;
            }
        }
        return true;
    };
    int ans = n;
    for (int i = 1; i <= n; i++)
        pre[i] = pre[i - 1], pre[i][s[i] - 'a']++;
    int lo = 1, hi = n;

    while (lo < hi - 1) {
        int mid = (lo + hi) >> 1;
        if (check(mid))
            hi = mid;
        else
            lo = mid;
    }
    cmin(ans, hi);
    reverse(ALL(s));
    for (int i = 1; i <= n; i++)
        pre[i] = pre[i - 1], pre[i][s[i] - 'a']++;
    lo = 1, hi = n;

    while (lo < hi - 1) {
        int mid = (lo + hi) >> 1;
        if (check(mid))
            hi = mid;
        else
            lo = mid;
    }
    cmin(ans, hi);
    cout << ans << '\n';
}