zoukankan      html  css  js  c++  java
  • 【cf比赛练习记录】Codeforces Round #579 (Div. 3)

    思考之后再看题解,是与别人灵魂之间的沟通与碰撞


    A. Circle of Students

    题意 给出n个数,问它们向左或者向右是否都能成一个环。比如样例5是从1开始向左绕了一圈 [3, 2, 1, 5, 4] 变成 [1, 2, 3, 4, 5];

    思路 我的方法是差分,假如成立,相邻两个数的差的绝对值要么是1要么是n-1。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<cstring>
    #include<string>
    #include<stack>
    using namespace std;
    
    int q, n;
    int num[202];
    int sum[202];
    
    int main()
    {
        cin >> q;
        while(q--){
            cin >> n;
            memset(sum, 0, sizeof(sum));
            for(int i = 0; i < n; i++) cin >> num[i];
    
            bool can = true;
            for(int i = 0; i < n; i++){
                if(i==0){
                    sum[i] = num[i] - num[n-1];
                }
                else {
                    sum[i] = num[i] - num[i-1];
                }
                if(abs(sum[i]) != 1 && abs(sum[i]) != n-1) can = false;
            }
    
            if(can) cout << "YES
    ";
            else cout << "NO
    ";
        }
        return 0;
    }
    
    

    B. Equal Rectangles

    题意 给出n个矩形,问所给出的4n条木棒所组成的矩形的面积是否都相等。

    分析 要使面积都相等,则要取中间值。先排个序,然后小的与大的在一起,从两头往中间靠拢。简单的实现。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<cstring>
    #include<string>
    #include<stack>
    using namespace std;
    
    int q, n;
    int num[402];
    int cnt[10004];
    
    int main()
    {
        cin >> q;
        while(q--){
            cin >> n;
            bool can = true;
            memset(cnt, 0, sizeof(cnt));
            for(int i = 0; i < 4*n; i++) {
                cin >> num[i];
                cnt[num[i]]++;
            }
            sort(num, num + 4*n);
    
            for(int i = 1; i <= 10000; i++){
                if(cnt[i]&1 == 1){ // 不清楚是否会有奇数边,所以遍历了一遍
                    can = false;
                    break;
                }
            }
    
            if(can){
                int sq = num[0] * num[4*n - 1]; // 两头
                int l = 2, r = 4*n - 3;
    
                for( ; l <= r; ){
                    if(num[l] * num[r] != sq){
                        can = false;
                        break;
                    }
                    l += 2; r -= 2;
                }
            }
    
            if(can) cout << "YES
    ";
            else cout << "NO
    ";
        }
        return 0;
    }
    
    

    C. Common Divisors

    题意 求n个数的公约数的个数。

    分析 先求最大公约数(gcd),然后求这个最大公约数的约数(花样找质数),注意long long。

    小插曲 因为我审题不认真,导致看漏了 Output 里的 "the number of...",结果卡了很久quq。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<cstring>
    #include<string>
    #include<stack>
    using namespace std;
    
    typedef long long LL;
    
    LL gcd(LL a, LL b){
        if(b == 0) return a;
        else return gcd(b, a%b);
    }
    
    int n;
    LL num[400005];
    
    int main()
    {
        scanf("%d", &n);
        for(int i = 0; i < n; i++) scanf("%I64d", &num[i]);
    
        LL ans = gcd(num[0], num[1]);
        for(int i = 2; i < n; i++){
            ans = gcd(ans, num[i]);
        }
    
        LL cnt = 0;
        for(LL i = 1; i*i <= ans; i++){
            if(i*i == ans) cnt += 1;
            else if(ans%i == 0) cnt += 2;
        }
        printf("%I64d
    ", cnt);
    
        return 0;
    }
    
    

    补题 D1. Remove the Substring (easy version)

    题意 t是s的子串,问最长可以删去s的连续子串后,仍保持t是s的子串。

    分析 注意,“the strings "test", "tst", "tt", "et" and "" are subsequences of the string "test". ”。然后因为数据小,可以暴力枚举被删子串的起点与终点。

    参考博客

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<cstring>
    #include<string>
    #include<stack>
    using namespace std;
    
    string s, t;
    int ans;
    
    int main()
    {
        cin >> s >> t;
        for(int i = 0; i < s.size(); i++){ // 被删子串起点
            for(int j = i; j < s.size(); j++){ // 被删子串终点
                int tt = 0;
                // 判断删后的子串是否仍满足条件------------
                for(int k = 0; k < s.size(); k++){
                    if(k == i){ // 遇到被删的起点立即跳到被删的终点
                        k = j;
                        continue;
                    }
                    if(s[k] == t[tt]){
                        tt++;
                        if(tt == t.size()){
                            break;
                        }
                    }
                }
                // -----------------------------------------
                if(tt == t.size()) ans = max(ans, j-i+1);
            }
        }
        cout << ans << endl;
        return 0;
    }
    
    

    补题 D2. Remove the Substring (hard version)

    题意 与D1一样,只是数据更大,不能暴力。

    分析 字符串的配对。经过D1的练手发现,可删去的最长连续子序列分别在t子序列的前、中、尾三个部分。思维有点像尺取法,请配合代码食用。

    参考博客

    #include<iostream>
    #include<cstdio>
    #include<string>
    using namespace std;
    
    string s, t;
    int pla[200005];
    
    int main()
    {
        cin >> s >> t;
        int j = 0, k = 1;
        pla[0] = -1;    // 有趣的操作
        for(int i = 0; i < s.size(); i++){
            if(j < t.size() && s[i] == t[j]){
                pla[k++] = i;   // 记录第一个子串的位置
                j++;
            }
        }
    
        for(int i = 0; i < k; i++){
            printf("i:%d pla[]:%d
    ", i, pla[i]);
        } cout << endl;
    
        int ans = 0;
        for(int i = s.size() - 1, j = 0; i >= 0; i--){
            ans = max(ans, i - pla[t.size() - j]);
            printf("i:%d j:%d pla[]:%d i-pla[]:%d
    ", i, j, pla[t.size() - j], i - pla[t.size() - j]);
            if(j < t.size() && s[i] == t[t.size() - j - 1]){    // 把t子串的末尾依次往前找
                j++;    // 请耐心思考一下
            }
        }
    
        cout << ans << endl;
        return 0;
    }
    
    

    补题 E.Boxers

    题意 在n个数里,可以对任意数+1或者-1或者不变,但是1不能变成0。问经过处理后的n个数里有多少个不同的数字。

    分析 利用桶排,都往下取,因为1不能减为0.(思考一下,非常简单)

    小插曲 我又看错题意了quq

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<cstring>
    #include<string>
    #include<stack>
    using namespace std;
    
    int n;
    int a[1500004];
    
    int main()
    {
        int num;
        cin >> n;
        for(int i = 0; i < n; i++){
            cin >> num;
            a[num]++;
        }
        int ans = 0;
        for(int i = 1; i <= 150001; i++){
            if(a[i-1]){
                ans++;
            }
            else if(a[i]){
                ans++;
                a[i]--; // 减1往下取,因为减1的数没有
            }
            else if(a[i+1]){
                ans++;
                a[i+1]--; // 同理
            }
        }
        cout << ans << endl;
        return 0;
    }
    
    

    补题 F1. Complete the Projects (easy version)

    题意 处理n个事件,每次处理时r必须不能小于(a_i),处理完后r的值会加上(b_i)的值((b_i)可以是负数),问是否能处理完n个事件,处理完时r不能小于0。

    分析 典型的贪心题目,需要排序。

    1. (b geq 0) 时,取a小的;
    2. (b leq 0) 时,取 a+b 大的。

    证明请看参考博客

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<cstring>
    #include<string>
    #include<stack>
    using namespace std;
    
    struct node{
        int a, b;
    }pro[102];
    int n, r;
    
    node one[102];
    node two[102];
    
    bool cmp1(node a, node b){
        return a.a < b.a;
    }
    
    bool cmp2(node a, node b){
        return a.a+a.b > b.a+b.b;
    }
    
    int main()
    {
        cin >> n >> r;
        int num, d, cnt1 = 0, cnt2 = 0;
        for(int i = 0; i < n; i++) {
            cin >> num >> d;
            node e; e.a = num; e.b = d;
            if(d >= 0){
                one[cnt1++] = e;
            }
            else {
                two[cnt2++] = e;
            }
        }
    
        sort(one, one + cnt1, cmp1);
        sort(two, two + cnt2, cmp2);
    
    //    cout << endl;
    //    for(int i = 0; i < cnt1; i++){
    //        cout << one[i].a << " " << one[i].b << endl;
    //    } cout << endl;
    //
    //    for(int i = 0; i < cnt2; i++){
    //        cout << two[i].a << " " << two[i].b << endl;
    //    } cout << endl;
    
        bool can = true;
        for(int i = 0; i < cnt1; i++){
            if(r < one[i].a){
                can = false;
                break;
            }
            else r += one[i].b;
        }
        for(int i = 0; i < cnt2; i++){
            if(r < two[i].a){
                can = false;
                break;
            }
            else r += two[i].b;
        }
        if(r < 0) can = false;
    
        if(can) cout << "YES
    ";
        else cout << "NO
    ";
    
        return 0;
    }
    
    
  • 相关阅读:
    06 | x86架构:有了开放的架构,才能打造开放的营商环境
    02 | 学习路径:爬过这六个陡坡,你就能对Linux了如指掌
    01 | 入学测验:你究竟对Linux操作系统了解多少?
    String、StringBuffer与StringBuilder区别
    JavaSE语言基础之字符串
    JavaSE语言基础之数组及其排序
    JavaSE语言基础之流程控制语句
    JavaSE语言基础之数据类型
    Java开发环境配置
    shell 脚本 自增
  • 原文地址:https://www.cnblogs.com/Ayanowww/p/11350283.html
Copyright © 2011-2022 走看看