【题解】Educational Codeforces Round 195 (Rated for Div. 2) ABCDE

Educational Codeforces Round 195 (Rated for Div. 2) 题解 ABCDE

比赛链接(codeforces)

官方题解(codeforces)

Problem A

  • a < b + 1 a < b + 1 a<b+1 时,无法凑出一个合法的三明治,输出 − 1 -1 −1。
  • a > = 2 b a >= 2b a>=2b 时,瓶颈在 b b b ,先凑出 b b b 个 "2A1B",多余的 A 随意处置,此时答案为 b b b。
  • 其余情况( 2 b > = a > = b + 1 2b >= a >= b+1 2b>=a>=b+1)时,瓶颈在 a,凑出 a − b − 1 a-b-1 a−b−1 个 "2A1B" 组合,此时剩下 2 b − a + 2 2b-a+2 2b−a+2 个 A 和 2 b − a + 1 2b-a+1 2b−a+1 个 B,恰好凑成一个,答案为 ( a − b − 1 ) + 1 (a-b-1)+1 (a−b−1)+1。
cpp 复制代码
#include<bits/stdc++.h>
#define int long long

using namespace std;

void solve(){
    int a,b;
    cin >> a >> b;
    if(a < b + 1){
        cout << -1 << '\n';
    }else if(a >= 2*b){
        cout << b << '\n';
    }else{
        cout << (a-b) << '\n';
    }
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);

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

Problem B

  • 最后的结果一定是 01 01 01 交替出现的字符串。因为第一个和最后一个字符固定, 01 01 01 交替串的开头结尾是固定的,只可能因为长度变化得到不同的 01 01 01 交替字符串。
  • 当出现连续3个相同字符,操作中间的,总长度可以增加2。
  • 当出现子串 010 010 010、 101 101 101 时,操作中间的,总长度可以减少2。
  • 什么都不做,总长度不变。
  • 综上,答案就是 1 1 1 ~ 3 3 3 的值,判断即可。
cpp 复制代码
#include<bits/stdc++.h>
#define int long long

using namespace std;

void solve(){
    string s;
    cin >> s;
    int ans = 1;
    bool flag1 = false,flag2 = false;
    for(int i = 1; i < (int)s.size() - 1; i ++){
        if(s[i] == s[i-1] && s[i] == s[i+1]){
            flag1 = true;
        }
        if(s[i] != s[i-1] && s[i] !=s[i+1]){
            flag2 = true;
        }
    }
    cout << ans + flag1 + flag2 << '\n';
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);

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

Problem C

  • 本题是经典套路题,用上这俩经典套路就行。
  • 1.如何处理长度 > k k k 这个信息?
    • 方法是在 i i i 的位置,更新 i − k i - k i−k 位置的信息。
    • 不难发现,这样操作后, i − k i-k i−k ~ i i i 这段长度不符合要求的位置,不可能对答案产生任何贡献。
  • 2.如何处理被 k k k 整除?
    • 方法是按找 m o d    k \mod k modk 产生的余数记录信息,对 k k k 同余的两个量,相减之后就可以被 k k k 整除了。
  • 完整方法:
    • 求前缀和,第 i i i 个位置的前缀和记为 s u m i sumi sumi.
    • 维护一个 m a p map map,称作 c n t cnt cnt, c n t s cnts cnts 表示当前状态(不包含长度小于 k k k的区间)下,前缀和 m o d    k \mod k modk 余 s s s 的位置个数。
    • 在第 i i i 个位置更新第 i − k i - k i−k 的信息到 c n t cnt cnt 里,更新方式为 c n t s u m \[ ( ( i − k ) − 1 ) cnt\[sum\[((i - k) - 1) % k] ++ cnt[sum[((i−k)−1)。
    • 以第 i i i 个位置结尾的答案就是 c n t s u m \[ i cntsum\[i % k] cntsum\[i。
cpp 复制代码
#include<bits/stdc++.h>
#define int long long

using namespace std;

void solve(){
    int n,k;
    cin >> n >> k;
    vector<int> a(n+1);
    for(int i = 1; i <= n; i ++){
        cin >> a[i];
    }
    map<int,int> cnt;

    vector<int> sum(n+1);
    for(int i = 1; i <= n; i ++){
        sum[i] = sum[i-1] + a[i];
    }
    int ans = 0;
    for(int i = 1; i <= n; i ++){
        if(i > k){
            int lastL = i - k;
            cnt[sum[lastL-1]%k] ++;
        }
        if(cnt.find(sum[i]%k) != cnt.end()){
            ans += cnt[sum[i]%k];
        }
    }
    cout << ans << '\n';
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);

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

Problem D

  • 出现度数为 0 0 0 的点,不可能合法,答案为 0 0 0,输出 "Brain Melt"。
  • 如果一个图的某种染色方案合法,那么将每个点的颜色取反(红变白,白变红)仍然合法,所以答案一定是偶数,不可能为 1 1 1。
  • 如果一个连通块中,度数 > = 2 >= 2 >=2 的点只有 1 1 1 个或没有。那么这个图只有 2 2 2 种染色方案。不同连通块间互补干扰,所以两个这样的连通块也能凑出 2 ∗ 2 2 * 2 2∗2 种方案输出 "Many" 了。
  • 如果一个连通块中,度数 > = 2 >= 2 >=2 的点不止 1 1 1 个,那么这个图有多种(> 2 2 2 种)染色方案。
cpp 复制代码
#include<bits/stdc++.h>
#define int long long

using namespace std;

void solve(){
    int n,m;
    cin >> n >> m;
    vector<int> deg(n+1);
    vector<vector<int>> v(n+1);
    for(int i = 1; i <= m; i ++){
        int x,y;
        cin >> x >> y;
        deg[x] ++,deg[y] ++;
        v[x].push_back(y);
        v[y].push_back(x);
    }
    for(int i = 1; i <= n; i ++){
        if(deg[i] == 0){
            cout << "Brain Melt\n";
            return;
        }
    }

    vector<int> done(n+1);
    int cnt = 0,cnt2 = 0;
    auto dfs = [&](auto &&self,int u) -> void{
        done[u] = 1;
        if(deg[u] >= 2) cnt2 ++;

        for(int i : v[u]){
            if(!done[i]){
                self(self,i);
            }
        }
    };

    int ans = 1;
    for(int i = 1; i <= n; i ++){
        if(!done[i]){
            cnt = 0,cnt2 = 0;
            dfs(dfs,i);
            if(cnt2 >= 2){
                ans *= 4;
            }else{
                ans *= 2;
            }

            if(ans > 2){
                cout << "Many\n";
                return;
            }
        }
    }
    cout << ans << '\n';

}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);

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

Problem E

官方题解思路与作者不同,官方题解更巧妙,使用贪心,下述方案思维难度小但码量大,使用DP。

官方题解(codeforces)

  • 先求 bad 子串,再用总数减,显然好一些。

  • 很容易猜到使用容斥原理, a ∩ b = a + b − a ∪ b a \cap b = a + b - a \cup b a∩b=a+b−a∪b。本题求的是 a − a ∩ b a - a \cap b a−a∩b。

  • 本题也就拆成了,求含 "2025" 的子串、含 "2026" 的子串以及含 "2025" 或 "2026" 的子串三部分。求的方法基本一样,求出一个后复制粘贴就行。

  • 可以dp求解。

    • 维护 d p l i j dplij dplij,表示考虑以 i i i 结尾的,能够提供目标字符串前 j − 1 j-1 j−1 个字符,不能够提供目标字符串前 j j j 的字符串个数。例如,求解 "2025" 时, d p l 10 2 dpl102 dpl102 表示以 10 10 10 个位置结尾的能够提供 "20" , 不能够提供 "202" 的字符串个数, d p l 10 3 dpl103 dpl103 表示能提供 "202" 的,不能够提供 "2025" 的字符串个数, d p l 10 0 dpl100 dpl100 表示什么都不能提供的字符串个数。
    • 转移法是遇到 '2','0','5','6'后,使用 d p l i − 1 j − 1 dpli-1j-1 dpli−1j−1 更新 d p l i j dplij dplij。其余情况只更新 d p i 0 dpi0 dpi0。
    • 维护 d p l i j dplij dplij,表示考虑以 i i i 开头的,能够提供目标字符串后 j − 1 j-1 j−1 个字符,不能够提供目标字符串后 j j j 的字符串个数。
    • 每个位置的答案,可以用 d p l dpl dpl, d p r dpr dpr 拼凑出。详情看转移方程。
    cpp 复制代码
        ans1[i] += (dpl[i-1][0]+1) * dpr[i][4];
        ans1[i] += dpl[i-1][1] * (dpr[i][4] + dpr[i][3]);
        ans1[i] += dpl[i-1][2] * (dpr[i][4] + dpr[i][3] + dpr[i][2]);
        ans1[i] += dpl[i-1][3] * (dpr[i][4] + dpr[i][3] + dpr[i][2] + dpr[i][1]);
        ans1[i] += dpl[i-1][4] * (dpr[i][4] + dpr[i][3] + dpr[i][2] + dpr[i][1] + dpr[i][0]);
    • 需要特别注意空串的情况。 +1 就是用来处理空串的。
  • 求出2025后,把代码中的数字5改成6,就求到了2026,把数字5改成5或6,就求到了2025或2026。

cpp 复制代码
#include<bits/stdc++.h>
#define int long long

using namespace std;

void solve(){
    int n;
    cin >> n;
    string s;
    cin >> s;
    s = "#" + s;
    vector<int> ans1(n+1),ans2(n+1),ans3(n+1);

    auto work1 = [&](){
        vector<vector<int>> dpl(n+1,vector<int>(5)),dpr(n+2,vector<int>(5));
        //2026
        for(int i = 1; i <= n; i ++){
            dpl[i][0] = dpl[i-1][0];
            dpl[i][1] = dpl[i-1][1];
            dpl[i][2] = dpl[i-1][2];
            dpl[i][3] = dpl[i-1][3];
            dpl[i][4] = dpl[i-1][4];
            if(s[i] == '2'){
                dpl[i][1] += dpl[i-1][0] + 1;
                dpl[i][0] = 0;
                dpl[i][3] += dpl[i-1][2];
                dpl[i][2] = 0;
            }else if(s[i] == '0'){
                dpl[i][0] += 1;
                dpl[i][2] += dpl[i-1][1];
                dpl[i][1] = 0;
            }else if(s[i] == '5'){
                dpl[i][0] += 1;
                dpl[i][4] += dpl[i-1][3];
                dpl[i][3] = 0;
            }else{
                dpl[i][0] += 1;
            }
        }

        for(int i = n; i >= 1; i --){
            dpr[i][0] = dpr[i+1][0];
            dpr[i][1] = dpr[i+1][1];
            dpr[i][2] = dpr[i+1][2];
            dpr[i][3] = dpr[i+1][3];
            dpr[i][4] = dpr[i+1][4];
            if(s[i] == '2'){
                dpr[i][2] += dpr[i+1][1];
                dpr[i][1] = 0;
                dpr[i][4] += dpr[i+1][3];
                dpr[i][3] = 0;
                dpr[i][0] += 1;
            }else if(s[i] == '0'){
                dpr[i][3] += dpr[i][2];
                dpr[i][2] = 0;
                dpr[i][0] += 1;
            }else if(s[i] == '5'){
                dpr[i][1] += dpr[i+1][0] + 1;
                dpr[i][0] = 0;
            }else{
                dpr[i][0] += 1;
            }
        }
        
        for(int i = 1; i <= n; i ++){
            ans1[i] += (dpl[i-1][0]+1) * dpr[i][4];
            ans1[i] += dpl[i-1][1] * (dpr[i][4] + dpr[i][3]);
            ans1[i] += dpl[i-1][2] * (dpr[i][4] + dpr[i][3] + dpr[i][2]);
            ans1[i] += dpl[i-1][3] * (dpr[i][4] + dpr[i][3] + dpr[i][2] + dpr[i][1]);
            ans1[i] += dpl[i-1][4] * (dpr[i][4] + dpr[i][3] + dpr[i][2] + dpr[i][1] + dpr[i][0]);
        }
    };
  

    auto work2 = [&](){
        vector<vector<int>> dpl(n+1,vector<int>(5)),dpr(n+2,vector<int>(5));
        //2026
    
        for(int i = 1; i <= n; i ++){
            dpl[i][0] = dpl[i-1][0];
            dpl[i][1] = dpl[i-1][1];
            dpl[i][2] = dpl[i-1][2];
            dpl[i][3] = dpl[i-1][3];
            dpl[i][4] = dpl[i-1][4];
            if(s[i] == '2'){
                dpl[i][1] += dpl[i-1][0] + 1;
                dpl[i][0] = 0;
                dpl[i][3] += dpl[i-1][2];
                dpl[i][2] = 0;
            }else if(s[i] == '0'){
                dpl[i][0] += 1;
                dpl[i][2] += dpl[i-1][1];
                dpl[i][1] = 0;
            }else if(s[i] == '6'){
                dpl[i][0] += 1;
                dpl[i][4] += dpl[i-1][3];
                dpl[i][3] = 0;
            }else{
                dpl[i][0] += 1;
            }
        }

        for(int i = n; i >= 1; i --){
            dpr[i][0] = dpr[i+1][0];
            dpr[i][1] = dpr[i+1][1];
            dpr[i][2] = dpr[i+1][2];
            dpr[i][3] = dpr[i+1][3];
            dpr[i][4] = dpr[i+1][4];
            if(s[i] == '2'){
                dpr[i][2] += dpr[i+1][1];
                dpr[i][1] = 0;
                dpr[i][4] += dpr[i+1][3];
                dpr[i][3] = 0;
                dpr[i][0] += 1;
            }else if(s[i] == '0'){
                dpr[i][3] += dpr[i][2];
                dpr[i][2] = 0;
                dpr[i][0] += 1;
            }else if(s[i] == '6'){
                dpr[i][1] += dpr[i+1][0] + 1;
                dpr[i][0] = 0;
            }else{
                dpr[i][0] += 1;
            }
        }
        
        for(int i = 1; i <= n; i ++){
            ans2[i] += (dpl[i-1][0]+1) * dpr[i][4];
            ans2[i] += dpl[i-1][1] * (dpr[i][4] + dpr[i][3]);
            ans2[i] += dpl[i-1][2] * (dpr[i][4] + dpr[i][3] + dpr[i][2]);
            ans2[i] += dpl[i-1][3] * (dpr[i][4] + dpr[i][3] + dpr[i][2] + dpr[i][1]);
            ans2[i] += dpl[i-1][4] * (dpr[i][4] + dpr[i][3] + dpr[i][2] + dpr[i][1] + dpr[i][0]);
        }
    };
    

    auto work3 = [&](){
        vector<vector<int>> dpl(n+1,vector<int>(5)),dpr(n+2,vector<int>(5));
        //2026
        
        for(int i = 1; i <= n; i ++){
            dpl[i][0] = dpl[i-1][0];
            dpl[i][1] = dpl[i-1][1];
            dpl[i][2] = dpl[i-1][2];
            dpl[i][3] = dpl[i-1][3];
            dpl[i][4] = dpl[i-1][4];
            if(s[i] == '2'){
                dpl[i][1] += dpl[i-1][0] + 1;
                dpl[i][0] = 0;
                dpl[i][3] += dpl[i-1][2];
                dpl[i][2] = 0;
            }else if(s[i] == '0'){
                dpl[i][0] += 1;
                dpl[i][2] += dpl[i-1][1];
                dpl[i][1] = 0;
            }else if(s[i] == '6' || s[i] == '5'){
                dpl[i][0] += 1;
                dpl[i][4] += dpl[i-1][3];
                dpl[i][3] = 0;
            }else{
                dpl[i][0] += 1;
            }
        }

        for(int i = n; i >= 1; i --){
            dpr[i][0] = dpr[i+1][0];
            dpr[i][1] = dpr[i+1][1];
            dpr[i][2] = dpr[i+1][2];
            dpr[i][3] = dpr[i+1][3];
            dpr[i][4] = dpr[i+1][4];
            if(s[i] == '2'){
                dpr[i][2] += dpr[i+1][1];
                dpr[i][1] = 0;
                dpr[i][4] += dpr[i+1][3];
                dpr[i][3] = 0;
                dpr[i][0] += 1;
            }else if(s[i] == '0'){
                dpr[i][3] += dpr[i][2];
                dpr[i][2] = 0;
                dpr[i][0] += 1;
            }else if(s[i] == '6' || s[i] == '5'){
                dpr[i][1] += dpr[i+1][0] + 1;
                dpr[i][0] = 0;
            }else{
                dpr[i][0] += 1;
            }
        }
        
        for(int i = 1; i <= n; i ++){
            ans3[i] += (dpl[i-1][0]+1) * dpr[i][4];
            ans3[i] += dpl[i-1][1] * (dpr[i][4] + dpr[i][3]);
            ans3[i] += dpl[i-1][2] * (dpr[i][4] + dpr[i][3] + dpr[i][2]);
            ans3[i] += dpl[i-1][3] * (dpr[i][4] + dpr[i][3] + dpr[i][2] + dpr[i][1]);
            ans3[i] += dpl[i-1][4] * (dpr[i][4] + dpr[i][3] + dpr[i][2] + dpr[i][1] + dpr[i][0]);
        }
    };
    work1();
    work2();
    work3();
    for(int i = 1; i <= n; i ++){
        cout << i * (n - i + 1) - (ans1[i] - (ans1[i] + ans2[i] - ans3[i])) << " \n"[i == n];
    }
    
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);

    int t = 1;
    cin >> t;
    while(t --){
        solve();
    }
}
相关推荐
Lhan.zzZ3 小时前
Qt WebEngineView 在 Linux 上无法加载网页:从“看不见 HTML“到“禁用沙箱“
linux·c++·qt
sysu_chenxy4 小时前
二重循环输出二维图形
c++
划破黑暗的第一缕曙光6 小时前
[C++]:2.类和对象(下)
c++·类和对象·对象·类
lvwangshu7 小时前
川剧复演 题解
动态规划·题解·技巧·性质题·思维好题
黎相思7 小时前
LRU Cache
c++·缓存
UIU1147 小时前
P1003 [NOIP 2011 提高组] 铺地毯
数据结构·c++·算法
xxwl5859 小时前
区域赛算法模版第四章---数据结构
数据结构·c++·算法
余额瞒着我当琳10 小时前
哈希表底层原理解析,直接定址法,哈希冲突,负载因子,哈希函数,开放定址法
java·c++·哈希算法·散列表
xxwl58511 小时前
区域赛算法模版第五章---数学与数论
c++·笔记·算法