Educational Codeforces Round 78 (Div. 2)

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

A - Shuffle Hashing

题意

给你两个由小写字母组成的字符串 p 和 h,问 h 中是否有连续子串可以由 p 打乱后生成。(1≤|p|, |h|≤100)

题解一

给字符串 p 和在 h 中的 p 长连续子串排序,比较是否有连续子串与 p 相等。

代码一

#include <bits/stdc++.h>
#define sz(x) int(x.size())
#define all(x) x.begin(), x.end()
using namespace std;

int solve() {
    string p, h; cin >> p >> h;
    sort(all(p));
    for (int i = 0; i + sz(p) <= sz(h); i++) {
        string sub_h = h.substr(i, sz(p));
        sort(all(sub_h));
        if (sub_h == p) return puts("YES");
    }
    puts("NO");
}

int main() {
    int t; cin >> t;
    while (t--) solve();
}

题解二

记录字符串 h 中每个位置 26 个字母的个数,比较字符串 h 中是否存在某个连续子串与字符串 p 中的字母个数相等。

代码二

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

void solve() {
    string p, h; cin >> p >> h;
    vector<int> cnt_p(26, 0);
    vector<vector<int>> cnt_h(105, vector<int>(26, 0));
    for (char c : p) {
        cnt_p[c - 'a']++;
    }
    for (int i = 1; i <= h.size(); i++) {
        cnt_h[i] = cnt_h[i - 1];
        cnt_h[i][h[i - 1] - 'a']++;
        for (int j = 0; j < i; j++) {
            vector<int> t(26);
            for (int k = 0; k < 26; k++) {
                t[k] = cnt_h[i][k] - cnt_h[j][k];
            }
            if (t == cnt_p) {
                cout << "YES" << "\n";
                return;
            }
        }
    }
    cout << "NO" << "\n";
}

int main() {
    int t; cin >> t;
    while (t--) solve();
}

B - A and B

题意

有正整数 a、b,第 i 次操作可以选择给一个数加 i,至少需要操作多少次才能使 a, b 相等。

题解

假设 b > a,若加上的数的总和小于 b - a 则一定无法使 a,b 相等,所以加上的数的总和需要大于等于 b - a。

若加上的总和大于 b - a,则多出来的这部分一定要可以平分为两份,即,给 a 加上 b - a + (sum - (b - a)) / 2,给 b 加上 (sum - (b - a)) / 2。

代码

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

bool ok(int n, int dif) {
    long long sum = (n + 1LL) * n / 2;
    return sum >= dif and (sum - dif) % 2 == 0;
}

void solve() {
    int a, b; cin >> a >> b;
    int dif = abs(b - a);
    int ans = 0;
    while (!ok(ans, dif)) ++ans;
    cout << ans << "\n";
}

int main() {
    int t; cin >> t;
    while (t--) solve();
}

C - Berry Jam

题意

有 2n 瓶草莓和蓝莓果酱,只能从一开始的中间处向左右连续一瓶一瓶地吃,问最少吃多少瓶果酱才能使剩下的草莓和蓝莓果酱瓶数相等。

题解

假设草莓比蓝莓多了 dif 瓶,向左连续吃的多了 l 瓶,向右连续吃的多了 r 瓶,即查找是否存在 l + r = dif 。

注意讨论左边或右边没吃的情况。

代码

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

const int M = 2e5 + 100;
int a[M];

void solve() {
    int n; cin >> n;
    int dif = 0;
    for (int i = 1; i <= 2 * n; i++) {
        cin >> a[i];
        dif += (a[i] == 1 ? 1 : -1);
    }

    map<int, int> lf, rt;
    int sum = 0;
    lf[0] = n + 1;//若只吃右边就可以解决,则会有 dif - r = 0,此时查询时返回右边第一个端点即可
    for (int i = n; i >= 1; i--) {
        sum += (a[i] == 1 ? 1 : -1);
        lf[sum] = max(i, lf[sum]);//对于左边来说,同一个差值离中间越近吃得越少,编号越大
    }
    sum = 0;
    rt[0] = n;//若只吃左边就可以解决,则会有 dif - l = 0,此时查询时返回左边最后一个端点即可
    for (int i = n + 1; i <= 2 * n; i++) {
        sum += (a[i] == 1 ? 1 : -1);
        rt[sum] = min(i, rt[sum]);//对于右边来说,同一个差值离中间越近吃得越少,编号越小
    }

    int ans = INT_MAX;
    for (auto l : lf) {
        auto r = rt.find(dif - l.first);
        if (r != rt.end()) {
            ans = min(ans, r->second - l.second + 1);
        }
    }
    cout << ans << "\n";
}

int main() {
    int t; cin >> t;
    while (t--) solve();
}

D - Segment Tree

题意

有 n 个位于 [1, 2n] 的区间,所有区间的端点各不相同(即 [1, 2n] 中的每个数都为某个区间的端点),如果有两个区间相交则这两个区间对应的两个编号间有一条边,问最后所有编号间能否组成一棵树。

题解

待填。

E - Tests for problem D

题意

与 D 题相反,给定一棵树找出 n 个满足 D 题意的区间。

题解

待填。

 

posted @ 2020-04-30 23:53  Kanoon  阅读(121)  评论(0)    收藏  举报