zoukankan      html  css  js  c++  java
  • CF 1500-1800训练 A

    题目链接

    A - Decrease the Sum of Digits

    思路:

    记录以下到那个位置会大于 (s),然后前一个位置的数加一,之后的全部变为零即可。

    注意特判到某个位置刚好等于 (s) 的情况。

    代码:
    int main(){
    
        int t; cin >> t;
        while(t --){
            string str; int s;
            cin >> str >> s;
            ll cur = 0;
            int lenStr = str.size();
            for(int i = 0; i < lenStr; i ++) cur = cur * 10 + str[i] - '0';
            int sum = 0, idx = -1;
            for(int i = 0; i < lenStr; i ++){
                sum += str[i] - '0';
                if(sum > s){
                    idx = i;
                    break;
                } else if(sum == s){
                    for(int j = i + 1; j < lenStr; j ++) sum += str[j] - '0';
                    if(sum > s){
                        idx = i;
                    }
                    break;
                }
            }
            if(idx == -1) puts("0");
            else{
                //cout << "idx = " << idx << endl;
                if(idx == 0){
                    str = '1' + str;
                    idx ++;
                } else{
                    str[idx - 1] ++;
                }
                lenStr = str.size();
                for(int i = idx; i < str.size(); i ++) str[i] = '0';
                ll now = 0;
                //cout << str << endl;
                for(int i = 0; i < lenStr; i ++) now = now * 10 + str[i] - '0';
                cout << now - cur << endl;
            }
        }
    
        
        return 0;
    }
    

    B - Two Platforms

    思路:

    显然 (y) 坐标是没有用的。

    (x) 坐标排序,预处理出 (cnt[i]) 数组,含义是 (i)(n) 之间放一个平台可以覆盖最多的点的数量。

    然后遍历一遍即可。

    代码:
    const int N = 2e5 + 10;
    
    int x[N], cnt[N];
    
    int main(){
    
       int t; cin >> t;
       while(t --){
           int n, k; cin >> n >> k;
           memset(cnt, 0, sizeof cnt);
           for(int i = 1; i <= n; i ++) scanf("%d", &x[i]);
           for(int i = 1, y; i <= n; i ++) scanf("%d", &y);
           sort(x + 1, x + n + 1);
           for(int i = n; i >= 1; i --){
               int mx = x[i] + k;
               int idx = upper_bound(x + 1, x + n + 1, mx) - x;
               cnt[i] = max(cnt[i + 1], idx - i);
           }
           int ans = 0;
           for(int i = 1; i <= n; i ++){
               int mx = x[i] + k;
               int idx = upper_bound(x + 1, x + n + 1, mx) - x;
               ans = max(ans, (idx - i) + cnt[idx]);
           }
           cout << ans << endl;
       }
    
       
       return 0;
    }
    
    

    C - Maximum Distributed Tree

    思路:

    把每条边的贡献算出来,然后贪心的赋值。

    代码:
    const int N = 1e5 + 10;
    const int mod = 1e9 + 7;
    
    vector<int> g[N];
    
    ll cnt[N];
    ll p[N], q[N];
    
    void dfs(int cur, int fa){
       cnt[cur] = 1;
       for(auto it : g[cur]){
           if(it == fa) continue;
           dfs(it, cur);
           cnt[cur] += cnt[it];
       }
    }
    
    
    int main(){
    
       int t; cin >> t;
       while(t --){
           int n, m; cin >> n;
           for(int i = 1; i <= n; i ++){
               g[i].clear();
               cnt[i] = 0;
               p[i] = 1;
           }
           for(int i = 1, u, v; i < n; i ++){
               scanf("%d %d", &u, &v);
               g[u].pb(v); g[v].pb(u);
           }
           cin >> m;
           for(int i = 1; i <= m; i ++) scanf("%lld", p + i);
           dfs(1, -1);
           m = max(m, n - 1);
           sort(p + 1, p + m + 1);
           for(int i = n; i <= m; i ++) p[n - 1] = p[n - 1] * p[i] % mod;
           for(int i = 1; i < n; i ++) q[i] = cnt[i + 1] * (n - cnt[i + 1]);
           sort(q + 1, q + n);
           ll ans = 0;
           for(int i = 1; i < n; i ++) 
               ans = (ans + (q[i] % mod * p[i] % mod) % mod) % mod;
           cout << ans << endl;
       }
       return 0;
    }
    
    

    D - RPG Protagonist

    思路:

    由于 (cnts) 不是很大,所以直接枚举某一个人选择 (sword) 的数量即可。

    代码:
    int main(){
    
        int t; input(t);
        while(t --){
            ll p, f, cnts, cntw, s, w;
            input(p); input(f);
            input(cnts); input(cntw);
            input(s); input(w);
            ll ans = 0;
            for(int i = 0; i <= cnts; i ++){
                ll tmp = i;
                ll rp = p - i * s;
                if(rp < 0) break;
                ll rcnts = cnts - i;
                ll getw = min(cntw, rp / w);
                ll rcntw = cntw - getw;
                tmp += getw;
                ll t1 = 0, t2 = 0;
                if(w < s){
                    ll getw = min(rcntw, f / w);
                    t1 = getw;
                    ll rf = f - getw * w;
                    t1 += min(rcnts, rf / s);
                } else{
                    ll gets = min(rcnts, f / s);
                    t2 = gets;
                    ll rf = f - gets * s;
                    t2 += min(rcntw, rf / w);
                }
                tmp += max(t1, t2);
                ans = max(ans, tmp);
            }
            cout << ans << endl;
            
        }
    
        
        return 0;
    }
    
    

    E - Binary String To Subsequences

    思路:

    分别记录出 (0, 1) 出现的位置,然后遍历一遍,对于当前出现的 (s[i]),直接二分去找下一个应该出现的字符((0)(1)(1)(0)),对于找到的字符,可以从记录的容器中删去。

    代码:
    const int N = 2e5 + 10;
    
    char s[N];
    int ans[N];
    
    vector<int> zero, one;
    
    int main(){
    
        int t; input(t);
        while(t --){
            
            int n; input(n);
            input(s + 1);
            for(int i = 1; i <= n; i ++){
                if(s[i] == '0') zero.pb(i);
                else if(s[i] == '1') one.pb(i);
            }
            
            memset(ans, 0, sizeof ans);
            int k = 0;
            
            for(int i = 1; i <= n; i ++){
                if(ans[i] == 0) ans[i] = ++ k;
                if(s[i] == '1'){
                    int idx = upper_bound(all(zero), i) - zero.begin();
                    if(idx >= zero.size()) continue;
                    if(zero[idx] > i && zero[idx] <= n) {
                        ans[zero[idx]] = ans[i];
                        zero.erase(zero.begin() + idx);
                    }
                } else{
                    int idx = upper_bound(all(one), i) - one.begin();
                    if(idx >= one.size()) continue;
                    if(one[idx] > i && one[idx] <= n) {
                        ans[one[idx]] = ans[i];
                        one.erase(one.begin() + idx);
                    }
                }
            }
    
            output(k);
            for(int i = 1; i <= n; i ++) printf("%d ", ans[i]);
            puts("");
            zero.clear();
            one.clear();
        }
    
    
        return 0;
    }
    
    

    F - Colored Rectangles

    思路:

    直接贪心的错误样例:

    r: 3 3
    g: 4
    b: 5
    
    wa = 20
    ac = 27
    
    

    (dp) 暴力则可以完整的枚举出所有的情况。

    (f[i][j][k]) :红色用来 (i) 个,绿色用了 (j) 个,蓝色用了 (k) 个的最大值。

    转移方程:

    [f[i+1][j+1][k] = max(f[i+1][j+1][k], f[i][j][k] + r[i] imes g[j]) ]

    [f[i+1][j][k+1] = max(f[i+1][j][k+1], f[i][j][k] + r[i] imes b[k]) ]

    [f[i][j+1][k+1] = max(f[i][j+1][k+1], f[i][j][k] + g[j] imes b[k]) ]

    代码:
    const int N = 210;
    
    int R[N], G[N], B[N];
    ll f[N][N][N];
    
    int main(){
    
        int r, g, b;
        input(r); input(g); input(b);
        for(int i = 1; i <= r; i ++) input(R[i]);
        for(int i = 1; i <= g; i ++) input(G[i]);
        for(int i = 1; i <= b; i ++) input(B[i]);
    
        auto cmp = [&](int a, int b) -> bool {
            return a > b;
        };
    
        sort(R + 1, R + r + 1, cmp);
        sort(G + 1, G + g + 1, cmp);
        sort(B + 1, B + b + 1, cmp);
    
        ll ans = 0;
    
        for(int i = 1; i <= r + 1; i ++)
            for(int j = 1; j <= g + 1; j ++)
                for(int k = 1; k <= b + 1; k ++){
                    f[i + 1][j + 1][k] = max(f[i + 1][j + 1][k], f[i][j][k] + R[i] * G[j]);
                    f[i + 1][j][k + 1] = max(f[i + 1][j][k + 1], f[i][j][k] + R[i] * B[k]);
                    f[i][j + 1][k + 1] = max(f[i][j + 1][k + 1], f[i][j][k] + B[k] * G[j]);
                    ans = max(ans, f[i][j][k]);
                }
        output(ans);
        
        return 0;
    }
    

    G - Good Subarrays

    思路:

    思维 + 前缀和

    已知:(sum[i] - sum[j - 1] = i - j + 1 = i - (j - 1))

    那么:(sum[i] - i = sum[j - 1] - (j - 1))

    显然我们只需要计算出 (sum[i] - i) 的个数即可。

    注:由于前面的公式涉及到了 (idx = 0) 的情况,所以 (sum[0] - 0) 也要算一个。

    代码:
    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e5 + 10;
    
    int sum[N];
    
    map<int, int> mp;
    
    int main(){
    
       int t; scanf("%d", &t);
       while(t --){
           mp.clear();
           int n; scanf("%d", &n);
           sum[0] = 0;
           for(int i = 1; i <= n; i ++){
               int x; scanf("%1d", &x);
               sum[i] = sum[i - 1] + x;
               mp[sum[i] - i] ++;
           }
           long long ans = 0;
           mp[0] ++;
           for(auto it : mp) {
               ans += 1ll * it.second * (it.second - 1) / 2;
           }
           cout << ans << endl;
       }
    
       return 0;
    }
    

    H - Same GCDs

    思路:

    (a > b) 时有:(gcd(a,b) = gcd(a-b,b))

    那么当 (a + x >= m) 时:(gcd(a + x) = gcd(a + x - m)).

    ((a + x) \% m)

    (y = (a + x) \% m)

    可得:(gcd(y, m) = gcd(a,m) = d)

    (gcd(y, m) = d) ,可得: (gcd(frac{y}{d}, frac{m}{d}) = 1)

    (n = frac{m}{d}),显然 (n) 是已知得,那么我们求得就是 ([2, n]) 中与 (n) 互质的数的个数,

    欧拉函数即可解决。

    代码:
    ll Euler(ll n){
        ll ans = n;
        for(ll i = 2; i * i <= n; i ++){
            if(n % i == 0) ans -= ans / i;
            while(n % i == 0) n /= i;
        }
        if(n > 1) ans -= ans / n;
        return ans;
    }
    
    int main(){
    
        int t; read(t);
        while(t --){
            ll a, m;
            cin >> a >> m;
            ll d = gcd(a, m);
           // out(toStr(d), d);
            cout << Euler(m / d) << endl;
        }
        return 0;
    }
    

    I - Ehab and Prefix MEXs

    思路:

    把未出现的数用 (b) 数组记录一下。

    如果 (a[i] == a[i - 1]) 则输出 (b) 中最小的数

    如果 (a[i] e a[i - 1]) 则输出 (a[i - 1])

    代码:
    int a[N], b[N], c[N];
    
    int main(){
    
        memset(c, 0, sizeof c);
        int n; cin >> n;
        for(int i = 1; i <= n; i ++) { cin >> a[i]; c[a[i]] = 1; }
        int cntb = 0;
        for(int i = 0; i <= n; i ++) if(!c[i]) b[ ++ cntb] = i;
        cntb = 0;
        a[0] = a[1];
        for(int i = 1; i <= n; i ++){
            if(a[i] == a[i - 1]) cout << b[ ++ cntb] << " ";
            else cout << a[i - 1] << " ";
        }
        return 0;
    }
    
    

    J - Skyscrapers (easy version)

    思路:

    显然要符合要求,那么曲线必然是先上升后下降(单增和单减属于特殊情况)。曲线即是: ^。

    那么我们直接暴力枚举最高点即可。

    时间复杂度:(O(n^2))

    代码:
        int n; cin >> n;
        vector<int> ans(n), tmp(n);
        ll h = 0;
        for(int i = 0; i < n; i ++) cin >> m[i];
        for(int i = 0; i < n; i ++){
            ll sum = 0;
            tmp[i] = m[i];
            sum += tmp[i];
            for(int j = i + 1; j < n; j ++)  { tmp[j] = min(m[j], tmp[j - 1]); sum += tmp[j]; }
            for(int j = i - 1; j >= 0; j --) { tmp[j] = min(m[j], tmp[j + 1]); sum += tmp[j]; }
            if(sum > h){
                ans = tmp;
                h = sum;
            }
        }
        for(int i = 0; i < n; i ++) cout << ans[i] << " ";
        cout << endl;
    

    K - Yet Another Walking Robot

    思路:

    用一个 (map) 来记录当前移动的状态,如果当前出现的状态在之前就已经出现过了,那么这一段的子串就可以合法删除。

    代码:
    const int N = 2e5 + 10;
    
    char s[N];
    
    int main(){
    
        int t; read(t);
        while(t --){
            int n; read(n);
            scanf("%s", s + 1);
            int x = 0, y = 0;
            map<PII, int> mp;
            int d = INF;
            PII ans;
            mp[{0, 0}] = 0;
            for(int i = 1; i <= n; i ++){
                if(s[i] == 'L') x --;
                else if(s[i] == 'R') x ++;
                else if(s[i] == 'U') y --;
                else y ++;
                if(mp.count({x, y}) && d > i - mp[{x, y}]){
                    d = i - mp[{x, y}];
                    ans = {mp[{x, y}] + 1, i};
                }
                mp[{x, y}] = i;
            }
            if(d == INF) puts("-1");
            else printf("%d %d
    ", ans.x, ans.y);
        }
        return 0;
    }
    

    L - Fight with Monsters

    思路:

    记录出每次都是我打死怪兽需要的最少令牌数,然后排个序,即可求出答案。

    代码:
    ll calc(ll a, ll b, ll x){
        ll t = x / (a + b);
        ll all = t * (a + b);
        if(all == x) t --;
        x -= t * (a + b);
        return x % a == 0 ? x / a - 1 : x / a;
    }
    
    int main(){
    
        ll n, a, b, k;
        cin >> n >> a >> b >> k;
        vector<ll> vec;
        for(int i = 1; i <= n; i ++){
            ll x; read(x);
            vec.pb(calc(a, b, x));
        }
        sort(all(vec));
        int ans = 0;
        for(int i = 0; i < sz(vec); i ++){
            k -= vec[i];
            if(k >= 0) ans ++;
            else break;
        }
        cout << ans << endl;
        return 0;
    }
    

    M - String Coloring (easy version)

    思路:

    当存在三个字符满足以下规律时:(zge yge x)(x, y, z是变量)),可以发现此时是无解的。所以我们可以根据这个来判断。

    根据以上的结论可以想到原字符串最多可以分为两个不递减子序列。

    代码:
    const int N = 2e2 + 10;
    
    char s[N];
    
    int main(){
    
        int n; read(n);
        scanf("%s", s + 1);
        string ans = "";
    
        char mx1 = 'a', mx2 = 'a';
    
        for(int i = 1; i <= n; i ++){
            if(s[i] >= mx1) { mx1 = s[i]; ans += '1'; }
            else if(s[i] >= mx2) { mx2 = s[i]; ans += '0'; }
            else {
                puts("NO");
                return 0;
            }
        }
        puts("YES");
        cout << ans << endl;
        return 0;
    }
    

    。。。

  • 相关阅读:
    msyql多个or,and,
    mysql中 where in 用法详解
    history.back(-1)和history.go(-1)的区别
    经典 mysql 28道题
    企业案例(二):增量恢复案例
    企业案例(一):由于mysql sleep线程过多小故障
    mysql数据库恢复
    binlog介绍
    mysql 数据库备份
    docker入门与实践
  • 原文地址:https://www.cnblogs.com/nonameless/p/13718791.html
Copyright © 2011-2022 走看看