• Codeforces Edu Round 65 A-E


    A. Telephone Number

    跟之前有一道必胜策略是一样的,(n - 10)位之前的数存在(8)即可。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int N = 110;
    int n;
    char s[N];
    int main(){
        int T; scanf("%d", &T);
        while(T--){
            scanf("%d%s", &n, s + 1);
            bool flag = false;
            for(int i = 1; i <= n - 10; i++)
                if(s[i] == '8') flag = true;
            if(flag) puts("YES");
            else puts("NO");
        }
        return 0;
    }
    

    B. Lost Numbers

    暴力枚举答案即可。

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int a[6] = {4, 8, 15, 16, 23, 42};
    int b[4];
    bool inline judge(){
        for(int i = 0; i < 4; i++)
            if(a[i] * a[i + 1] != b[i]) return false;
        return true;
    }
    int main(){
        for(int i = 1; i <= 4; i++){
            printf("? %d %d
    ", i, i + 1);
            fflush(stdout);
            scanf("%d", b + i - 1);
        }
        do{
            if(judge()){
                printf("! ");
                for(int i = 0; i < 6; i++)
                    printf("%d ", a[i]);
                puts("");
                fflush(stdout);
                break;
            }
        }while(next_permutation(a, a + 6));
        return 0;
    }
    

    C. News Distribution

    这...不是并查集裸题吗?

    #include <iostream>
    #include <cstdio>
    using namespace std;
    const int N = 500010;
    int n, m, f[N], size[N];
    int inline find(int x){
        return f[x] == x ? x : f[x] = find(f[x]);
    }
    void inline merge(int x, int y){
        x = find(x), y = find(y);
        if(x == y) return ;
        if(size[x] > size[y]) swap(x, y);
        f[x] = y; size[y] += size[x];
    }
    int main(){
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) {
            f[i] = i, size[i] = 1;
        }
        for(int i = 1; i <= m; i++){
            int k, x; scanf("%d", &k);
            if(!k) continue;
            scanf("%d", &x); 
            for(int j = 1, y; j < k; j++){
                scanf("%d", &y);
                merge(x, y);    
            }
        }
        for(int i = 1; i <= n; i++)
            printf("%d ", size[find(i)]);
        return 0;
    }
    

    D. Bicolored RBS

    维护一个变量(dep),表示目前在第一层,只要奇偶异置,则符合要求,最大层数为(lceil maxDep / 2 ceil)

    #include <cstdio>
    #include <iostream>
    #include <stack>
    using namespace std;
    const int N = 200010;
    char str[N];
    int n, ans[N], dep = 0;
    int main(){
        scanf("%d%s", &n, str + 1);
        for(int i = 1; i <= n; i++){
            if(str[i] == '('){
                ans[i] = (++dep) & 1;
            }else if(str[i] == ')'){
                ans[i] = (dep--) & 1;
            }
        }
        for(int i = 1 ;i <= n; i++) 
            printf("%d", ans[i]);
        return 0;
    }
    

    E. Range Deleting

    (Two - Pointer)算法。我们发现两个性质:

    1. ((l, r))可行,那么((l, r + 1) , (l, r + 2)...(l, x))都是可行的。因为在升序序列删东西还是升序的。

    2. ((l, r))不可行,那么((l, r - 1) , (l, r - 2)...(l, l))都是不可行的。因为在已经不可行的序列加东西显然不想。

    那么,对于每一个(l (1 <= l <= x)),我们找出一个最小的(r)使其满足条件,左端点为(l)对答案的贡献就是(n - r + 1)。我们称这个最小的(r)(r_{min_l})

    还有另外一个性质,在(l)增加之后,(r_{min_l})只可能增加或不变,不可能减少。因为多露出数,要么符合条件,要么还需要减掉一些数。

    想到这里,我们就可以用双指针算法了。我们还需要用(O(1))的时间判断加入一个数是否可行。

    我们可以用(O(n))的时间预处理四个数组:

    1. (S_i) 代表数字(i)在数组中出现最早的位置
    2. (T_i) 代表数字(i)在数组中出现最晚的位置
    3. (Sx_i) 代表数字(i)(x)在数组中出现最早的位置
    4. (Tx_i) 代表数字(1)(i)在数组中出现最晚的位置
    • 对于左端(l)的处理,若我们想知道让(l - 1)移动到(l)是否可行:

    (Tx[l - 2] < S[l - 1]),则小于(l - 1)的一切数位置都在第一个(l - 1)左边,就可以移动。

    • 对于右端点的处理,已确定([1, l - 1])([r + 1, x])范围内的数均满足条件,判断((l, r)),是否满足条件:

    (Tx_{l - 1} < Sx_{r + 1})表示所有小于等于(l - 1)的数都在大于(r + 1)的数的左边则满足条件,否则我们需要让(r)增加。

    注意,在处理当中我们先找到一个最小的(r)使得((1, r))满足条件,然后在扩大(l)的1过程当中,被迫增加(r),如性质(2)

    #include <cstdio>
    #include <iostream>
    #include <cmath>
    #include <cstring>
    using namespace std;
    const int N = 1000010, INF = 0x3f3f3f3f;
    typedef long long LL;
    int n, x, S[N], T[N], Sx[N], Tx[N];
    int a[N];
    LL ans = 0;
    int main(){
        memset(S, 0x3f, sizeof S);
        scanf("%d%d", &n, &x);
        for(int i = 1; i <= n; i++){
            scanf("%d", a + i);
            if(S[a[i]] == INF) S[a[i]] = i;
            T[a[i]] = i;
        }
        for(int i = 1; i <= x; i++)
            Tx[i] = max(Tx[i - 1], T[i]);
        
        Sx[x + 1] = INF;
        for(int i = x; i; i--)
            Sx[i] = min(Sx[i + 1], S[i]);
        
        int r = x - 1;
        while(r && T[r] < Sx[r + 1]) r--;
        for(int l = 1; l <= x; l++){
            if(l > 2 && S[l - 1] < Tx[l - 2]) break;
            while(r <= x && (r < l || Tx[l - 1] > Sx[r + 1])) 
                r++;
            ans += x - r + 1;
        }
        printf("%lld
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    文件的上传
    扩展HTTP管道
    发布开源框架iOS矢量图形框架 TouchVG
    批量修改文件名的py脚本
    《矢量绘图基础》PPT
    开题了《面向移动设备的交互式图形平台设计与实现》
    计算几何(转)
    批量替换文件名和内容的Python脚本
    iOS上的二维绘图软件现状
    基本图形手绘图形算法包
  • 原文地址:https://www.cnblogs.com/dmoransky/p/11311781.html
Copyright © 2020-2023  润新知