• Educational Codeforces Round 103 (Rated for Div. 2) A~D题解


    写在前边

    链接:Educational Codeforces Round 103 (Rated for Div. 2)

    A. K-divisible Sum

    链接:A题链接

    题目大意:

    要求构造一个(a)数组使得(a)的和可以被(k)整除,在这个条件下让(a)中的最大值尽可能小。

    思路

    我是这样想的,就是n张牌组成(k),比如要求(4)张牌组成(5, 6, 7, 8)那么数组里最大的数最小肯定是(2),但是如果(8 < k leq 12),那么就是(3...)了,而对于(n < k)的,我们想办法先让(k > n),然后再与上面同理,所以我是分类讨论的:
    (n < k)时,那么最大的那个数就是(k / n),如果无法整除则需要向上取整, 即(k / n + (k \% n == 0 ? 0 : 1))
    (k = n)时,那么最大的数最小肯定就是(k / n = 1)了。
    (n > k)时,那么我们可以先让(k > n),即(k = k * (n / k + (n \% k == 0 ? 0 : 1))),然后就与第一种情况同理了。

    看到好多被(hack)的代码也是用这种思路,但是没有考虑无法整除向上取整的问题。

    顺便新学了一招:(q = lceil cfrac{n}{k} ceil = lfloor cfrac{n + k - 1}{k} floor),这样向上取整就用不着再用三目运算符啦!

    代码:

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <unordered_map>
    
    using namespace std;
    
    #define Inf 0x3f3f3f3f
    #define PII pair<int, int>
    #define P2LL pair<long long, long long>
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector<long long> VLL;
    typedef vector<int> VI;
    
    void solve() {
        LL n, k;
        cin >> n >> k;
        if (n > k) {
            LL t1 = n / k;
            k = k * (t1 + (n % k == 0 ? 0 : 1));
            LL t2 = k / n;
            cout << t2 + (k % n == 0 ? 0 : 1) << '
    ';
            return;
        } else if (k == n) {
            cout << 1 << endl;
            return;
        } else {
            LL t2 = k / n;
            cout << t2 + (k % n == 0 ? 0 : 1) << '
    ';
        }
    }
    
    int main()
    {
        ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
        int t;
        cin >> t;
        while (t--) {
            solve();
        }
    
        return 0;
    } 
    

    B. Inflation

    链接:B题链接

    题目大意:

    修改一个序列,让其通货膨胀系数不能超过(k%),输出序列修改了多少。
    (p_i)的通货膨胀系数:(k_i = cfrac{p_i}{p_1 + p_2 + ... + p_{i-1}}),求出最小的修改数。

    思路

    看到这个题因为枚举到后边的时候我们只关心前缀和就可以,不用具体关心前边某一个元素该怎么变化,所以就想到了前缀和,但是还是因为浮点数问题,其实类似问题已经在(atc)中一场比赛意识到了,遇到除法能不用小数就不用,比如判断是否合理的时候可以转化成乘法判断(a[i] * 100 <= s[i-1] * k),最后终于修改的差不多了,还是有一个地方没有处理好,赛后才看到一个人代码恍然大悟,除不尽的时候应该向上取整的,可惜了。
    向上取整还是用这种方法:(q = lceil cfrac{n}{k} ceil = lfloor cfrac{n + k - 1}{k} floor)

    代码:

    一开始的核心代码是这样的,用数组(s)来维护前缀和,但是每次都要再维护一下前缀和,明显增加了时间复杂度。

    void deal(int k, LL temp) {
        for (int i = k; i <= n; i++) {
            s[i] += temp;
        }
    }
     
    void solve() {
        cin >> n >> k;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
            s[i] = s[i - 1] + a[i];
        }
        LL sum = 0;
        for (int i = 2; i <= n; i++) {
            if (a[i] * 100 <= s[i-1] * k) {
                continue;
            } else {
                LL temp = (a[i] * 100 - k * s[i-1]) / k;
                temp = (a[i] * 100 - k * s[i-1]) % k == 0 ? temp : temp + 1;
                sum += temp;
                deal(i - 1, temp); //处理前缀和
            }
        }
     
        cout << sum << endl;
    }
    

    后来优化了很多,包括代码的长短,以及用一个变量来维护前缀和。

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <unordered_map>
    #include <cmath>
    
    using namespace std;
    
    #define Inf 0x3f3f3f3f
    #define PII pair<int, int>
    #define P2LL pair<long long, long long>
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector<long long> VLL;
    typedef vector<int> VI;
    
    const int N = 110;
    LL a[N];
    LL n, k;
    
    void solve() {
        cin >> n >> k;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
        }
        LL sum = 0, preSum = a[1];
        for (int i = 2; i <= n; i++) {
            if (a[i] * 100 > preSum * k) {
                LL temp = (a[i] * 100 - k * preSum + k - 1) / k;
                sum += temp;
                preSum += temp;
            }
            preSum += a[i];
        }
    
        cout << sum << endl;
    }
    
    int main()
    {
        //ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
        int t;
        cin >> t;
        while (t--) {
            solve();
        }
    
        return 0;
    } 
    

    C. Longest Simple Cycle

    链接:C题链接

    题目大意:

    不描述原题了,有点难描述。。

    思路

    因为我们求得一个圈的长度,而一个圈的右边必然右一条链组成,所以我们从第二条链往后枚举每一条链,对于每一个圈的右半部分长度就是(c[i] + 1),而对于左半部分,如果(a_i == b_i)那么就说明右半部分重合到一点了,否则就是(abs(a_i - b_i)),维护一个(curlen)以及一个(lastlen),对于(a_i != b_i)的时候,我们可以判断一下左边的环与右边的环接起来是否会更大,如果更大就把中间的(abs(a_i - b_i))去掉,即(curlen = max(curlen, c[i] + 1 + lastlen - abs(a[i] - b[i]))),然后更新(res)以及(lastlen)即可

    代码:

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <unordered_map>
    
    using namespace std;
    
    #define Inf 0x3f3f3f3f
    #define PII pair<int, int>
    #define P2LL pair<long long, long long>
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector<long long> VLL;
    typedef vector<int> VI;
    
    const int N = 2e5 + 10;
    LL c[N], a[N], b[N];
    
    void solve() {
        int n;
        cin >> n;
        for (int i = 0; i < n; i++) {
            cin >> c[i];
        }
        for (int i = 0; i < n; i++) {
            cin >> a[i];
        }
        for (int i = 0; i < n; i++) {
            cin >> b[i];
        }
        LL res = 0, curlen = 0, lastlen = 0;
        for (int i = 1; i < n; i++) {
            curlen = c[i] + 1 + abs(a[i] - b[i]);
            if (a[i] != b[i]) {
                curlen = max(curlen, c[i] + 1 + lastlen - abs(a[i] - b[i]));
            }
            res = max(res, curlen);
            lastlen = curlen;
        }
        cout << res << endl;
    }
    
    int main()
    {
        ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
        int t;
        cin >> t;
        while (t--) {
            solve();
        }
    
        return 0;
    } 
    

    D. Journey

    链接:D题链接

    题目大意:

    给定一组(n)个道路的方向,链接了(n + 1)个城市,旅游时只能按照道路方向旅游,同时走一次道路那么所有的道路就反向一次,比如原来道路方向只能是(A->B),但是到(B)之后道路会反向,所以然后还可以从(B)返回(A),求从每一个城市可以旅行到的最多城市。

    思路

    一种是利用本题的性质,因为去还可以回来,所以可以说是一种无向边,但是并查集((DSU)),(BFS),(DFS)代码我看了一上午,实在看不懂,想不明白。
    于是用递推的方式做了,即用(dpl_i)表示(i)城市从(i)城市向左可以最多走到的城市标号,用(dpr_i)表示从(i)城市向右可以最多走到的城市标号,最后答案就是(num_i = dpr_i -dpl_i +1),只不过要注意的细节比较多。
    对于(dpl_i)

    1. 如果不能向左走,那么:(dpl_i = i)
    2. 如果能向左走一步那么:(dpl_i = i-1)
    3. 然后就可以直接转移了:(dpl_i = dpl_{i-2})
      对于(dpr_i)同理,从后向前递推即可。

    代码:

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    
    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;
    
    const int N = 3E5 + 10;
    char s[N];
    int n;
    int dpl[N], dpr[N];
    
    void solve() {
        scanf("%d", &n);
        scanf("%s", s + 1);
        for (int i = 1; i <= n + 1; i++) {
            dpl[i] = i;
        }
        for (int i = 1; i <= n + 1; i++) {
            dpr[i] = i;
        }
        for (int i = 1; i <= n + 1; i++) {
            if (i == 1 || s[i - 1] == 'R') { //向左走不动
                dpl[i] = i; 
            } else if (i == 2 || s[i - 2] == 'L') { //向左只能走一格
                dpl[i] = i - 1; 
            } else {
                dpl[i] = dpl[i - 2];
            }
        }
        for (int i = n + 1; i >= 1; i--) {
            if (i == n + 1 || s[i] == 'L') {
                dpr[i] = i;
            } else if (i == n || s[i + 1] == 'R') {
                dpr[i] = i + 1;
            } else {
                dpr[i] = dpr[i + 2];
            }
        }
        for (int i = 1; i <= n + 1; i++) {
            printf("%d ", dpr[i] - dpl[i] + 1);
        }
        puts("");
    }
    
    int main()
    {
        //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
        int t;
        scanf("%d", &t);
        while (t--) {
            solve();
        }
    
        return 0;
    } 
    
  • 相关阅读:
    知识图谱学习与实践(4)——通过例句介绍Sparql的使用
    知识图谱学习与实践(3)——知识表示
    知识图谱学习与实践(2)——知识图谱数据模型的构建
    知识图谱学习与实践(1)——知识图谱的演化过程
    NIO客户端主要创建过程
    NIO服务端主要创建过程
    Relative path in absolute URI: ${system:java.io.tmpdir%7D/$%7Bhive.session.id%7D_resources
    ubuntu中mysql安装失败
    使用ant build build.xml报“includeantruntime was not set”警告及"Class not found: javac1.8"问题
    maven编译报错 -source 1.5 中不支持 lambda(或diamond) 表达式,编码 UTF-8 的不可映射字符
  • 原文地址:https://www.cnblogs.com/ZhengLijie/p/14352415.html
Copyright © 2020-2023  润新知