• Codeforces Round #702 (Div. 3) 题解


    写在前边

    链接:Codeforces Round #702 (Div. 3)
    比较简单,但是总是感觉脑子有点转不过弯来。

    A. Dense Array

    链接:A题链接

    题目大意:

    在数组中插入若干个数,使得(cfrac{max(a[i], a[i + 1])}{min(a[i], a[i + 1])} leq 2),问至少需要插入多少个数。

    思路

    既然是相邻,那么只需要顺序模拟即可,每次把(min(a[i], a[i + 1])×2), 直到它的两倍大于等于(2)停止,求累计次数。

    代码

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <map>
    #include <cstring>
    
    using namespace std;
    
    #define Inf 0x3f3f3f3f
    #define PII pair<int, int>
    #define P2LL pair<long long, long long>
    #define endl '
    '
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector<long long> VLL;
    typedef vector<int> VI;
    
    LL gcd(LL a, LL b) {
        return b ? gcd(b, a % b) : a;
    }
    
    const int N = 55;
    
    void solve() {
        int n;
        int a[N];
        scanf("%d", &n);
        for (int i = 0; i < n; i++) scanf("%d", &a[i]);
    
        int res = 0;
        for (int i = 1; i < n; i++) {
            if (max(a[i], a[i - 1]) > 2 * min(a[i], a[i - 1])) {
                int m = min(a[i], a[i - 1]);
                while (m * 2 < max(a[i], a[i - 1])) {
                    res++;
                    m *= 2;
                } 
            }
        }
        printf("%d
    ", res);
    }
    
    int main()
    {
        //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
        int t;
        scanf("%d", &t); 
        while (t--) {
            solve();
        }
        return 0;
    }
    

    B. Balanced Remainders

    链接:B题链接

    题目大意:

    给定一个有(n)(n可以被3整除)个元素的数组,(c_0,c_1,c_2)分别表示数组中元素模(3)后的余数为(0, 1, 2)的数的个数,现在每次操作可以使一个数加(1),问最少经过几次操作可以使得(c_0 == c_1 == c_2)

    思路

    可以发现,(c_0, c_1, c_2)之间可以进行单一方向的转移,例如模(3)余数为(0)的数加(1)后余数变为(1),余数为(1)的数加(1)后余数变为(2),余数为(2)的数加(1)后余数变为(0)
    ,于是问题就转化成了转移多少次的问题,相邻的转移又一定是最优的。

    代码

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <map>
    #include <cstring>
    #include <unordered_map>
    
    using namespace std;
    
    #define Inf 0x3f3f3f3f
    #define PII pair<int, int>
    #define P2LL pair<long long, long long>
    #define endl '
    '
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector<long long> VLL;
    typedef vector<int> VI;
    
    LL gcd(LL a, LL b) {
        return b ? gcd(b, a % b) : a;
    }
    
    const int N = 3e4 + 10;
    int a[N];
    
    void solve() {
        int n;
        scanf("%d", &n);
        unordered_map<int, int> hash;
        int cnt0 = 0, cnt1 = 0, cnt2 = 0;
        for (int i = 0; i < n; i++) {
            scanf("%d", &a[i]);
            hash[a[i] % 3]++;
        }
    
        int aver = n / 3;
        int res = 0;
        while (1) {
            if (hash[1] == hash[2] && hash[1] == hash[0] && hash[0] == hash[2]) {
                break;
            }
            if (hash[1] < aver) {
                hash[0] -= (aver - hash[1]);
                res += (aver - hash[1]);
                hash[1] = aver;
            }
            if (hash[2] < aver) {
                hash[1] -= (aver - hash[2]);
                res += (aver - hash[2]);
                hash[2] = aver;
            }
            if (hash[0] < aver) {
                hash[2] -= (aver - hash[0]);
                res += (aver - hash[0]);
                hash[0] = aver;
            }
        }
        printf("%d
    ", res);
    }
    
    int main()
    {
        //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
        int t;
        scanf("%d", &t);
        while (t--) {
            solve();
        }
        return 0;
    }
    

    C. Sum of Cubes

    链接:C题链接

    题目大意:

    判断一个数(x)是否满足(x = a^3 + b^3 \, (a, b geq 1))

    思路

    因为数据最大为(10^{12}),所以(a,b in [1, 10^4)),所以一种做法是预处理出(a^3),然后再(O(10^4))枚举(b)(O(1))查找(a^3)
    另一种方法是(O(10^4))枚举(a),二分(b),复杂度(O(10^4 * log 10^4))

    代码

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <map>
    #include <cstring>
    
    using namespace std;
    
    #pragma GCC optimize(2)
    #pragma GCC optimize(3,"Ofast","inline")
    
    #define Inf 0x3f3f3f3f
    #define PII pair<int, int>
    #define P2LL pair<long long, long long>
    #define endl '
    '
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector<long long> VLL;
    typedef vector<int> VI;
    
    LL gcd(LL a, LL b) {
        return b ? gcd(b, a % b) : a;
    }
    
    void solve() {
        LL x;
        scanf("%lld", &x);
        LL t1;
        for (LL i = 1; i <= 10000; i++) {
            LL l = 1, r = 10000;
            while (l < r) {
                LL mid = l + r >> 1;
                LL sum = i * i * i + mid * mid * mid;
                if (sum > x) r = mid;
                else if (sum < x) l = mid + 1;
                else {
                    puts("YES");
                    return;
                } 
            }
        }
        puts("NO");
    }
    
    int main()
    {
        //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
        int t;
        scanf("%d", &t); 
        while (t--) {
            solve();
        }
        return 0;
    }
    

    D. Permutation Transformation

    链接:D题链接

    题目大意:

    给定一个数组,用其数据建一棵树,最大的数始终作为树根,树根左侧数构成左子树,右边的数构成右子树,同理选大的作为子树的根,求每个数在树中所处的深度。

    思路

    (DFS)

    代码

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <map>
    #include <cstring>
    
    using namespace std;
    
    #define Inf 0x3f3f3f3f
    #define PII pair<int, int>
    #define P2LL pair<long long, long long>
    #define endl '
    '
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector<long long> VLL;
    typedef vector<int> VI;
    
    LL gcd(LL a, LL b) {
        return b ? gcd(b, a % b) : a;
    }
    
    const int N = 110;
    int a[N];
    int res[N];
    int n;
    
    void build(int l, int r, int depth) {
        if (l > r) return;
    
        int idx = l;
        for (int i = l; i <= r; i++) {
            if (a[i] > a[idx]) idx = i;
        }
        res[idx] = depth;
        build(l, idx - 1, depth + 1);
        build(idx + 1, r, depth + 1);
    }  
    
    void solve() {
        scanf("%d", &n);
        for (int i = 0; i < n; i++) scanf("%d", &a[i]);
    
        build(0, n - 1, 0);
    
        for (int i = 0; i < n; i++) printf("%d ", res[i]);
        puts("");
    }
    
    int main()
    {
        //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
        int t;
        scanf("%d", &t); 
        while (t--) {
            solve();
        }
        return 0;
    }
    

    E. Accidental Victory

    链接:E题链接

    题目大意:

    (n)个玩家,每人都有一个点数,两个人对战,点数大的获胜,相同点数随机一人获胜,获胜后获得败者的点数,问有哪些人会有获胜的可能性。

    思路

    一个人要想获胜,那么肯定需要干掉所有的人才可以,首先按照点数给人排序,我们发现对于第i个人它可以直接获得它之前人的所有点数,这里可以用前缀和处理,如果可以赢得比赛,那么他后边的人也一定能赢得比赛,因为他后边的人可以获得更多的点数,所以可以发现有二段性,因此我们可以直接二分出第一个获胜的人,剩下的直接输出即可。

    代码

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <map>
    #include <cstring>
    
    using namespace std;
    
    #define Inf 0x3f3f3f3f
    #define PII pair<int, int>
    #define P2LL pair<long long, long long>
    #define endl '
    '
    #define score first
    #define num second
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector<long long> VLL;
    typedef vector<int> VI;
    
    LL gcd(LL a, LL b) {
        return b ? gcd(b, a % b) : a;
    }
    
    const int N = 2e5 + 10;
    LL b[N];
    int n;
    PII a[N];
    
    bool check(int x) {
        LL t = b[x];
        for (int i = x + 1; i <= n; i++) {
            if (t >= a[i].score) {
                t += (LL) a[i].score;
                continue;
            }
            else return false;
        }
        return true;
    }
    
    void solve() {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i].score);
            a[i].second = i;
        }
        sort(a + 1, a + n + 1);
    
        for (int i = 1; i <= n; i++) b[i] = b[i - 1] + (LL) a[i].score;
        int l = 1, r = n;
        while (l < r) {
            int mid = l + r >> 1;
            if (check(mid)) r = mid;
            else l = mid + 1; 
        }
        vector<int> res;
        for (int i = l; i <= n; i++) res.push_back(a[i].num);
        sort(res.begin(), res.end());
    
        printf("%d
    ", n - l + 1);
        for (auto &it : res) printf("%d ", it);
        puts("");
    }
    
    int main()
    {
        //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
        int t;
        scanf("%d", &t); 
        while (t--) {
            solve();
        }
    
        return 0;
    }
    

    F. Equalize the Array

    链接:F题链接

    题目大意:

    (cnt_x)为数组中每个数的出现次数,如果一个数组中的数只有(C)次或者(0)次可以认为这个数组是漂亮的,所以我们现在要做的就是删掉某些数使得这个数组是漂亮的。

    思路

    按照题意,(cnt_x)小于(C)(x)那么全部删除,大于(C)的需要删除(cnt_x - C)个,所以有:

    [删除个数 = sumlimits_{cnt_x < C} cnt_x + sumlimits_{cnt_x >= C} (cnt_x - C) ]

    看到这个公式能想到什么,当然是前缀和。
    但是有一个问题,(C)的范围一定是某个数的出现次数吗,如果不是,那么就没法用前缀和做了,那怎么证明呢,如果(C)不是某个数的出现次数,我们令某个刚好大于(C)的次数为(Y),可以发现,(sumlimits_{cnt_x < C} cnt_x)没有发生变化,而大于(sumlimits_{cnt_x >= C} (cnt_x - C) > sumlimits_{cnt_x >= Y} (cnt_x - Y)),这样于是删除个数变大了,所以我们根本不需要考虑如果(C)不是某个数的出现次数这种情况。

    有了前缀和(presum),根据公式,左边就有(left = presum[i - 1]), 右边就有(right = (presum[last] - presum[i - 1]) - (last - i + 1) * cnt[i]),于是更新答案即可。

    代码

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <map>
    #include <cstring>
    
    using namespace std;
    
    #define Inf 0x3f3f3f3f
    #define PII pair<int, int>
    #define P2LL pair<long long, long long>
    #define endl '
    '
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector<long long> VLL;
    typedef vector<int> VI;
    
    LL gcd(LL a, LL b) {
        return b ? gcd(b, a % b) : a;
    }
    
    const int N = 2e5 + 10;
    int n, c;
    LL presum[N];
    
    bool cmp(int a, int b) {
        return a > b;
    }
    
    void solve() {
        scanf("%d", &n);
        map<LL, LL> mp;
        for (int i = 0; i < n; i++) {
            scanf("%d", &c);
            mp[c]++;
        }
        
        vector<LL> cnt; //计数 数字出现的次数 
        for (auto &it : mp) cnt.push_back(it.second);
        cnt.push_back(0);
        sort(cnt.begin(), cnt.end()); 
        
        LL res = n;
        int last = cnt.size() - 1;
        for (int i = 1; i < cnt.size(); i++) presum[i] = presum[i - 1] + cnt[i];
        for (int i = 1; i <= last; i++) {
            LL left = presum[i - 1], right = (presum[last] - presum[i - 1]) - (last - i + 1) * cnt[i];
            res = min(res, left + right);
        }
        printf("%d
    ", res);
    }
    
    int main()
    {
        //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
        int t;
        scanf("%d", &t); 
        while (t--) {
            solve();
        }
    
        return 0;
    }
    

    G - Old Floppy Drive

    链接:G题链接

    题目大意:

    现在有个含有(n)个元素的数组(a),且有一个指针指向(a)的初始,还有一个(m)个元素的数组(x),对于每一个(x_i),指针会不停的运动,如果数组末尾那么它会重新指会第一个元素继续运动,直到指针走过的数组所有元素的和(≥x),那么指针停止,求指针的运动次数。

    思路

    设数组总和为(S),前缀和为(preSum),运行一次的时间是(T),那么运行(t)秒,那么走过的总和(Sum)

    [Sum = lfloor cfrac{t}{T} floor * S + preSum \, [t \, mod \, T] ]

    由此可见,如果(S leq 0) 并且 (maxlimits_{i = 1}^n \, preSum[i] < x)那么指针将永远运行下去不会停止,那么直接输出(-1)即可。

    然后就分别求磁盘转动的整圈数,然后再加上(maxlimits_{i = 1}^n \, preSum[i] geq x)的最小位置(i),可以知道,对于磁盘的转动整圈数不得少于(lceil frac{x - maxlimits_{i = 1}^n \, preSum[i] \, }{S} ceil),少于转不到,多于的话也就不能保证答案是最小位置了。

    最后就需要找到(maxlimits_{i = 1}^n \, preSum[i] geq x)的位置(i)了,可以用二分,注意这个前缀和并不是随随便便的前缀和,处理它的时候保证它是单调递增的且(>0),如果小于等于(0)那么对总和(Sum)没有任何贡献,并且单调递增才能保证我们可以得到那个刚好(maxlimits_{i = 1}^n \, preSum[i] geq x)的位置(i),而这一步我们可以用二分lower_bound寻找即可。

    代码

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <map>
    #include <cstring>
    
    using namespace std;
    
    #define Inf 0x3f3f3f3f
    #define PII pair<int, int>
    #define P2LL pair<long long, long long>
    #define endl '
    '
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector<long long> VLL;
    typedef vector<int> VI;
    
    LL gcd(LL a, LL b) {
        return b ? gcd(b, a % b) : a;
    }
    
    const int N = 2e5 + 10;
    int n, m;
    LL presum[N];
    LL preInd[N]; //记录前缀的坐标
    
    void solve() {
        int idx = 0; //当前坐标
        LL allsum = 0, c;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) {
            scanf("%lld", &c);
            allsum += c; 
            if (allsum > presum[idx]) {
                presum[++idx] = allsum;
                preInd[idx] = i;
            }
        }
    
        for (int i = 1; i <= m; i++) {
            LL x;
            scanf("%lld", &x);
            if (presum[idx] < x && allsum <= 0) {
                printf("%d ", -1);
                continue;
            }
            LL needspins = 0;
            if (presum[idx] < x) {
                needspins = (x - presum[idx] + allsum - 1) / allsum;
            }
            x -= needspins * allsum;
            LL q = lower_bound(presum + 1, presum + idx + 1, x) - presum;
            LL res = needspins * n + preInd[q] - 1; //因为前缀从1开始,那么减去1
            printf("%lld ", res);
        }
        puts("");
    }
    
    int main()
    {
        //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
        int t;
        scanf("%d", &t);
        while (t--) {
            solve();
        }
    
        return 0;
    }
    
  • 相关阅读:
    File Types过滤Maven项目目录
    Idea中main方法不能正常运行
    《Effective C++》rule 02: Prefer consts, enums, and inlines to #defines
    《Effective C++》 rule 03: Use const whenever possible
    《Effective C++》rule 01: View C++ as a federation of languages
    洛谷B2001 入门测试题目
    SecurityRandom随机数生成
    Java垃圾回收(GC)机制详解
    如何在 Linux 上查找哪个线程cpu利用率最高
    win10自动更新关闭
  • 原文地址:https://www.cnblogs.com/ZhengLijie/p/14418248.html
Copyright © 2020-2023  润新知