Codeforces 820 Div3

T1
题意:两个电梯,电梯1:直接从a楼前往1楼; 电梯2:从b楼到c楼再到1楼,问那个电梯时间更短

直接模拟即可

点击查看代码
#include<bits/stdc++.h>
 
using i64 = long long;
 
int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
 
    int t; std::cin >> t;
 
    while(t--){
        int a, b, c; std::cin >> a >> b >> c;
        int x = a - 1, y = std::abs(b - c) + c - 1;
        std::cout << (x < y ? 1 : x == y ? 3 : 2 )<< '\n';
    }
 
    return 0;
}

T2
将一个数字字符串解码为英文字符串,加密规则:若字母<10,直接转换为该数字,>0转换为数字后加个0

对应解码:从后往前遍历,若遇到零,则取前两位数字转换为对应字母,若不为0,则直接转换为对应字母

点击查看代码
#include<bits/stdc++.h>
 
using i64 = long long;
 
int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
 
    int t; std::cin >> t;
 
    while(t--){
        int n; std::cin >> n;
        std::string s; std::cin >> s;
        std::vector<char> in;
        for(int i = n - 1; i >= 0; --i){
            if(s[i] == '0'){
                int x = (s[i - 2] ^ 48) * 10 + (s[i - 1] ^ 48);
                in.push_back(x - 1 + 'a');
                i -= 2;
            }else{
                in.push_back((s[i] ^ 48) - 1 + 'a');
            }
        }
        std::reverse(in.begin(), in.end());
        for(auto x : in){
            std::cout << x;
        }   std::cout << '\n';
 
    }
 
    return 0;
}

T3
给定一个字符串,从开头走至结尾,每个位置只能走一次,跳跃代价为字母差的绝对值,求最小代价,同时在最小代价的前提下,取最大步数。

取26个桶记录每个字母数量,则从开头字母到末尾字母的最小代价记为开头桶到结尾同的有值解,最大步数记为这些桶的个数和

点击查看代码
#include<bits/stdc++.h>
 
using i64 = long long;
 
int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
 
    int t; std::cin >> t;
 
    while(t--){
        std::string s; std::cin >> s;
 
        char a = s[0], b = s.back();
 
        std::vector<int> v(26);
        std::vector<int> op[26];
        for(int i = 0; i < (int)s.size(); ++i){
            v[s[i] - 'a']++;
            op[s[i] - 'a'].push_back(i + 1);
        }
 
        int ans = 0, step = 0;
        char pre = '-';  std::vector<int> lx;
        for(char x = a; a <= b ? x <= b : x >= b; a <= b ? ++x : --x){
            if(v[x - 'a']){
                step += v[x - 'a'];
                if(pre == '-'){
                    pre = x;
                }else{
                    ans += std::abs((int)(x - pre));
                    pre = x;
                }
                for(auto xx : op[x - 'a']){
                    lx.push_back(xx);
                }
            }
        }
 
        std::cout << ans << ' ' << step << '\n';
        for(auto x  : lx){
            std::cout << x << ' ';
        }   std::cout << '\n';
 
 
    }
 
    return 0;
}

T4

共n人,每人消费xi, 有yi元,至少两人组队,且队内总钱数必须大于等于总消费,问最多可以组成多少个队?

处理出每个人盈余后排序,尽可能让盈余正的与最能与其组队的负盈余组队,若还有正盈余的再两两组队

点击查看代码
#include<bits/stdc++.h>
 
using i64 = long long;
 
int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
 
    int t; std::cin >> t;
 
    while(t--){
        int n; std::cin >> n;
 
        std::vector<int> x(n), y(n);
        for(int i = 0; i < n; ++i){
            std::cin >> x[i];
        }
        for(int j = 0; j < n; ++j){
            std::cin >> y[j];
        }
 
        std::vector<int> z(n); int p = n;
        for(int i = 0; i < n; ++i){
            z[i] = y[i] - x[i];
        }
        std::sort(z.begin(), z.end());
 
        for(int i = 0; i < n; ++i){
            if(z[i] >= 0 && p == n){
                p = i;
            }
        }
 
        int ans = 0;
        for(int i = 0, j = n - 1; i < p; ++i){
            if(j >= p && z[i] + z[j] >= 0){
                --j;
                ++ans;
            }
        }
        ans += (n - p - ans) / 2;
        std::cout << ans << '\n';
    }
 
    return 0;
}

T5
交互题:有n个点形成一个圆,最多50次交互,求n
交互规则:?a b 得到a b之间有多少条边
若a <= n && b <= n (1 / 2概率获取其中一个边数)
否则得到-1

从前往后顺序交互?1 : i 和 ? i : 1
如果都为-1则得到 i- 1
如果x != y 得到x + y
50次得概率(0.5)^ (50)很小

点击查看代码
#include<bits/stdc++.h>
 
using i64 = long long;
 
int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
 
    i64 x, y;
    for(int i = 4; i <= 30; ++i){
        std::cout << "? " << 1 << ' ' << i << std::endl;
        std::cin >> x;
        std::cout << "? " << i << ' ' << 1 << std::endl;
        std::cin >> y;
        if(x == -1 && y == -1){
            std::cout << "! " << i - 1 << std::endl;
            return 0;
        }
        if(x != y){
            std::cout << "! " << x + y << std::endl;
            return 0;
        }
    }
    return 0;
}

T6

求最小的L1, L2使得v(L1, L1 + w - 1) * v(l, r) + v(L2, L2 + w - 1)与k模9同余

处理出长度为w最早的余9为i的L进行处理即可

点击查看代码
#include<bits/stdc++.h>
 
using i64 = long long;
 
int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
 
    int t; std::cin >> t;
 
    while(t--){
        std::string s; std::cin >> s;
 
        int n = (int)s.size();
        std::vector<int> a(n);
        for(int i = 0; i < n; ++i){
            a[i] = (s[i] ^ 48) % 9;
        }
 
        std::vector<int> pre(n); pre[0] = a[0];
        for(int i = 1; i < n; ++i){
            pre[i] = (pre[i - 1] + a[i]) % 9;
        }
 
        int w, m; std::cin >> w >> m;
 
        std::vector<std::vector<int>> check(9);
        for(int i = 0; i + w - 1 < n; ++i){
            int j = i + w - 1;
            int now = ((pre[j] - (i == 0 ? 0 : pre[i - 1])) % 9 + 9) % 9;
            check[now].push_back(i + 1);
        }
 
        for(int i = 0; i < m; ++i){
            int l, r, k; std::cin >> l >> r >> k; --l, --r;
            int x = ((pre[r] - (l == 0 ? 0 : pre[l - 1])) % 9 + 9) % 9;
            int l1 = -1, l2 = -1, key = 0;
            for(int ii = 0; ii < 9; ++ii){
                for(int jj = 0; jj < 9; ++jj){
                    if(check[ii].empty() || check[jj].empty() || (ii * x + jj) % 9 != k){
                        continue;
                    }
                    if(ii == jj && check[ii].size() == 1){
                        continue;
                    }
                    if(l1 == -1 || (check[ii][0] < l1) || (check[ii][0] == l1 && check[jj][0] < l2)){
                        l1 = check[ii][0];
                        l2 = ii == jj ? check[jj][1] : check[jj][0];
                    }
                }
            }
            std::cout << l1 << ' ' << l2 << '\n';
        }
 
    }
 
    return 0;
}

T7

给定s,t,破坏s中出现的某些t,使得s中再没有t子串,求最小破坏数,同时在最小破坏数的前提下求有多少种方案数?

考虑dp,见代码

点击查看代码
#include<bits/stdc++.h>

using i64 = long long;
constexpr int P = (int)1e9 + 7;

int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int t; std::cin >> t;

    while(t--){
        std::string a, b; std::cin >> a >> b;

        int n = a.size(), m = b.size();

        std::vector<int> c(n); int p = -1;
        for(int i = 0; i + m - 1 < n; ++i){
            if(a.substr(i, m) == b){
                c[i] = 1;
                p = i;
            }
        }

        std::vector<std::pair<int, int>> dp(n + 1, {n + 1, 0});
        dp[0] = {0, 1};
        for(int i = 0; i < n; ++i){
            for(int j = i; j + m <= n; ++j){
                if(j - i >= m && c[j - m]){
                    break;
                }
                if(c[j]){
                    if(dp[i].first + 1 < dp[j + m].first){
                        dp[j + m] = dp[i];
                        dp[j + m].first = (dp[i].first + 1) % P;
                    }else if(dp[i].first + 1 == dp[j + m].first){
                        dp[j + m].second = (dp[i].second + dp[j + m].second) % P;
                    }
                }
            }
        }

        std::pair<int, int> ans{n + 1, 0};
        for(int i = p + 1; i <= n; ++i){
            if(dp[i].first == ans.first){
                ans.second = (ans.second + dp[i].second) % P;
            }else if(dp[i].first < ans.first){
                ans = dp[i];
            }
        }

        std::cout << ans.first << ' ' << ans.second << '\n';
    }

    return 0;
}
posted on 2022-09-13 17:30  航海士  阅读(18)  评论(0)    收藏  举报