• Codeforces Global Round 13


    第一次打Codeforces Global Round系列的比赛,感觉比赛时间太长了,时间太晚了,2个小时就溜了。。

    A. K-th Largest Value

     A题链接

    本来以为这个需要使用 快排扩展,求解第K个数字,细看一下题目,因为数据非 0,即 1

    可以直接统计 0, 1数量进行求解。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 100010;
    int a[N];
    int num[2];
    int n, q;
    
    int main()
    {
        cin >> n >> q;
        num[0] = num[1] = 0;
        for (int i = 1; i <= n; i ++ )
            scanf("%d", &a[i]),
            num[a[i]] ++;
    
        while (q -- ) {
            static int x, y;
            scanf("%d %d", &x, &y);
            if (x == 1) {
                num[a[y]] --;
                a[y] = 1 - a[y];
                num[a[y]] ++;
            } else {
                if (num[1] >= y)
                    puts("1");
                else
                    puts("0");
            }
        }
        return 0;
    }
    

    B. Minimal Cost

    B题链接 

    行数为 n((nleq100)), 列数为(10^6+2)

    因为 each row 有且仅有一个 obstacle,首先我们考虑什么时候才会堵住,因为列数太多,因此我们只能 竖向堵住,具体操作如图所示:

    或者是倾斜的前进,总之,不能够让 S 可以从左侧到 右侧。因为一旦过去,就可以到 (col=10^6+1)进而移动到 终点 E 。

    对于(row=cur) 障碍物所在位置为(x),倘若想要堵住,那么(row=cur+1)位置就需要变成(x 或 x + 1 或 x - 1).

    划分清楚如何堵住之后,考虑一下 cost 代价的最小值

    • 未堵住, (cost = 0)

    • 倘若 (a_1=a_2=...=a_n),那么移动的最小代价即为 (v + min(u, v))横向移动一次,在进行一次横向移动,或者是竖向移动。

    • 否则, (cost=min(u, v)),因为对于任何一种存在斜对角的方案,可以通过横向移动,也可以通过竖向移动产生路径。

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    const int N = 110;
    int a[N];
    int num[2];
    int n;
    LL u, v;
    
    int main()
    {
        int t; cin >> t;
        LL res = 0;
        while (t -- ) {
            scanf("%d%lld%lld", &n, &u, &v);
            for (int i = 1; i <= n; i ++ )
                scanf("%d", &a[i]);
            res = 0;
            bool flag = false;
            bool allSame = true;
            for (int i = 2; i <= n; i ++ ) {
                if (a[i] != a[i - 1])
                    allSame = false;
                if (a[i] == a[i - 1] || a[i] == a[i-1] + 1 || a[i] == a[i-1] - 1)
                    continue;
                else {
                    flag = true;
                    break;
                }
            }
    
            if (!flag) {    // 不能直接过去
                if (allSame) {
                    res = v + min(u, v);
                } else {
                    res = min(u, v);
                }
            } else {
                res = 0;
            }
    
    
            printf("%lld
    ", res);
        }
    
        return 0;
    }
    		
    

    C. Pekora and Trampoline

    C题链接

    可以通过 (O(N^2))的算法进行解决。

    首先,对于一个 trampoline ,当他 strength 减到 1之前,它能跳跃到其他的pos是固定的,长度减到一之后,就到 (pos + 1)位置。下面我们采取以下办法:

    • 对于 trampoline ,我们从 1 ~ n 进行循环
      • 设当前标号为 cur,他的初始强度为 (S_i),我们可以统计标号 1~(cur-1) 经过 i 的次数为 (B_i)
      • 倘若 (B_ileq S_i),那么需要以 i 为起点还需要的次数为 (S_i - 1 - B_i),将他累加到答案中
      • 否则,不需要单独以 i trampoline 作为起点
      • 下面我们需要更新 cur ~ N 号 蹦蹦床的 (B_i),即从之前节点经过的次数
        • (B_ileq S_i-1),对 cur + 2 ~ min(cur + S_i, n)进行更新,(B_i += 1)
        • (B_igeq S_i-1),对 cur + 2 ~ min(cur + S_i, n)进行更新,(B_i += 1),, 同时(B_{cur+1} +=B_i-(S_i-1))

    上面的算法,主要是求出了以每个节点作为最少起点次数的数量,然后累加求和得到了最小次数。

    代码如下

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    const int N = 5010;
    int a[N];
    int b[N];
    int n;
    
    int main()
    {
        int t; cin >> t;
        while (t -- ) {
            scanf("%d", &n);
            for (int i = 1; i <= n; i ++ ) {
                scanf("%d", &a[i]);
            }
    
            memset(b, 0, sizeof b);
    
            LL res = 0;
            for (int i = 1; i <= n; i ++ ) {
                if ((a[i] - 1) >= b[i]) {   // a[i] - 1 是本身所需要的次数
                    res += (a[i] - 1) - b[i];
                    for (int j = 2; j <= a[i]; j ++ ) {
                        if (j + i < N) {    // 跳跃的位置
                            b[i + j] ++;
                        } else {
                            break;
                        }
                    }
                } else {
                    for (int j = 2; j <= a[i]; j ++ ) {
                        if (j + i < N) {    // 跳跃的位置
                            b[i + j] ++;
                        } else {
                            break;
                        }
                    }
                    b[i + 1] += b[i] - (a[i] - 1);
                }
            }
    
    
            cout << res << endl;
        }
    
        return 0;
    }
    

    D. Zookeeper and The Infinite Zoo

    D题链接

    通过查看数据范围,感觉 DP打表啥的都不行,数据量太大了,因此只能按照原理从二进制01串入手。

    • 首先,若(u = v),肯定可以到达

    • 其次,若(u>v),那么肯定无法到达,因为只有低下标向高下标才存在路径。

    • 最后,我们讨论当 (u < v),如何才可以到达

      主要就是将从低位到高位,不断向目标串看齐,向上传递

      不过当,当前位 = 1,低位向高位也传递了 1, 而目标是0,

      此时有两种选择

      • 两个 1 直接相加,向高位传递一个1
      • 两个 1 各自向高位传递一个 1

      因为两种方法都是可选了,而且我们也不想dfs,可以直接 传递一个 1, 然后加一个可选量 1,可用可不用即可。

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    const int N = 5010;
    
    // u <= v
    bool Check(LL u, LL v) {
        if (u > v)  return false;
        if (u == v) return true;
    
        int x, y, sx = 0, sy = 0;
        LL maxHave = 0;
        for (int i = 0; i <= 34; i ++ ) {
            x = ((u >> i) & 1);
            y = ((v >> i) & 1);
            // printf("I:%d, %d
    ", x, y);
            x += sx, sx = 0;
            y += sy, sy = 0;	// sy 其实没啥用
            // printf("I:%d, %d
    ", x, y);
            if (x == y)
                continue;
            else if (x < y) {   // y = 1, x = 0
                if (maxHave == 0)
                    return false;
                else {
                    maxHave -= 1;
                }
            }
            else {  // x > y, (1, 0), (2, 0), (2, 1)
                sx = 1;
                if (x == 2 && y == 0)   // 可选值增加
                    maxHave += 1;
            }
        }
        return true;
    }
    
    int main()
    {
        int t; cin >> t;
    
        LL u, v;
        while (t -- ) {
            scanf("%lld%lld", &u, &v);
            // if (u > v)  swap(u, v);
    
            if (Check(u, v))
                puts("YES");
            else
                puts("NO");
        }
    
        return 0;
    }
    
    
  • 相关阅读:
    [BZOJ2212][POI2011]Tree Rotations(线段树合并)
    [BZOJ3569]DZY Loves Chinese II(随机化+线性基)
    [BZOJ3237][AHOI2013]连通图(分治并查集)
    [BZOJ4945][NOI2017]游戏(2-SAT)
    [BZOJ4568][SCOI2016]幸运数字(倍增LCA,点分治+线性基)
    [BZOJ2460][BJOI2011]元素(线性基)
    [BZOJ4942][NOI2017]整数(线段树+压位)
    [P2023][AHOI2009]维护序列(线段树)
    [HDU4336]Card Collector(min-max容斥,最值反演)
    [COGS2426][HZOI 2016]几何
  • 原文地址:https://www.cnblogs.com/lucky-light/p/14462439.html
Copyright © 2020-2023  润新知