• Codeforces Round #634 (Div. 3)


    链接:https://codeforces.com/contest/1335

    A - Candies and Two Sisters

    B - Construct the String

    C - Two Teams Composing

    题意:给n个数,要求找到一个x,使得可以从n个数中先选出一个x个数的无重集合,再选出一个x个相同的数的集合。

    题解:统计一下最多的相同的数有几个,记为A1,并且要记录最多的相同的数有几种,记为A2,然后考虑一共有多少种不同的数,记为B。

    举几个例子:

    1 2 3 4 5 6
    3 3 3 3 3 3
    
    1 2 3 4 5 6
    3 3 3 3 3 3 3
    

    这种情况,代表A1>=B+1,这种时候受B限制,且可以分A1的一个过去第一个集合,答案是B。

    1 2 4 5 6
    3 3 3 3 3
    
    1 2 4 5 6
    3 3 3 3
    

    这种情况,代表A1<=B-1,这种时候答案是A1。

    还差一种情况,A1=B,这种时候是A1-1。

    1 2 4
    3 3 3 3
    

    D - Anti-Sudoku

    题意:给出一个数独,改动其中的至多9个数字,使得其满足:

    每行都有至少2个相同元素。
    每列都有至少2个相同元素。
    分成九宫格的每个格都有至少2个相同元素。

    题解:没说要保持数字的总数不变啊?直接把所有的'2'都换成'1'。

    char s[15];
    void TestCase() {
        for(int i = 1; i <= 9; ++i) {
            scanf("%s", s + 1);
            for(int j = 1; j <= 9; ++j) {
                if(s[j] == '2')
                    s[j] = '1';
            }
            puts(s + 1);
        }
    }
    

    F - Robots on a Grid

    题意:给一个格子图,每个格子上面有标有一个方向“上下左右”其中之一,这个方向不会指引越界。这些格子有些是黑格有些是白格,求最多能放多少个机器人,以及最多能放多少个机器人在黑格。机器人被放在格子图上,沿着格子指引的方向同时移动,当两个机器人在某个时刻撞在一个格子上时是非法的放置方法,(但是他们可以撞在格子边界上)。

    题解:这个格子图明显是一篇基环树森林,容易知道“最多能放多少个机器人”就是基环树森林的所有的环的的大小。麻烦的在于求“最多能放多少个机器人在黑格”,想到一个好办法,当发现一个基环树的环之后,从这个环上的任意一点开始dfs染色,深度从[1,M]循环,M是这个基环树的环的大小,容易发现染色相同的格子是只能放一个机器人的,这时就判断这些格子中是否有至少一个黑色格就可以了。

    int n, m;
     
    int id(int i, int j) {
        return (i - 1) * m + j;
    }
     
    int U(int id) {
        return id - m;
    }
     
    int D(int id) {
        return id + m;
    }
     
    int L(int id) {
        return id - 1;
    }
     
    int R(int id) {
        return id + 1;
    }
     
    int top;
    char s[1000005];
    int C[1000005];
    int G[1000005];
    vector<int> BG[1000005];
     
    int color[1000005], cntcolor;
     
    vector<int> CurCircle;
     
    int incircle;
    void dfs(int u, int c) {
        if(color[u]) {
            if(color[u] == c) {
                incircle = u;
                return;
            }
            return;
        }
        color[u] = c;
        dfs(G[u], c);
        if(incircle) {
            CurCircle.push_back(u);
            if(u == incircle) 
                incircle = 0;
        }
        return;
    }
     
    int ans1, ans2;
     
    int CntBlack[1000005], M;
    int vis[1000005];
     
    void DFS(int u, int dep) {
        if(vis[u])
            return;
        vis[u] = 1;
        if(C[u] == 0) {
            if(CntBlack[dep] == 0) {
                CntBlack[dep] = 1;
                ++ans2;
            }
        }
        if(dep == M)
            dep = 0;
        for(auto &v : BG[u])
            DFS(v, dep + 1);
        return;
    }
     
    void Solve2() {
        M = CurCircle.size();
        DFS(CurCircle[0], 1);
        for(int i = 0; i <= M; ++i)
            CntBlack[i] = 0;
    }
     
    void Solve() {
        ans1 = 0, ans2 = 0;
        cntcolor = 0;
        for(int i = 1; i <= n * m; ++i) {
            if(!color[i]) {
                ++cntcolor;
                CurCircle.clear();
                dfs(i, cntcolor);
                if(CurCircle.size()) {
                    ans1 += CurCircle.size();
                    Solve2();
                }
            }
        }
        printf("%d %d
    ", ans1, ans2);
    }
     
    void TestCase() {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n * m; ++i) {
            BG[i].clear();
            vis[i] = 0;
            color[i] = 0;
        }
        top = 0;
        for(int i = 1; i <= n; ++i) {
            scanf("%s", s + 1);
            for(int j = 1; j <= m; ++j)
                C[++top] = s[j] - '0';
        }
        top = 0;
        for(int i = 1; i <= n; ++i) {
            scanf("%s", s + 1);
            for(int j = 1; j <= m; ++j) {
                ++top;
                if(s[j] == 'U') {
                    G[top] = U(id(i, j));
                    BG[U(id(i, j))].push_back(id(i, j));
                } else if(s[j] == 'D') {
                    G[top] = D(id(i, j));
                    BG[D(id(i, j))].push_back(id(i, j));
                } else if(s[j] == 'L') {
                    G[top] = L(id(i, j));
                    BG[L(id(i, j))].push_back(id(i, j));
                } else if(s[j] == 'R') {
                    G[top] = R(id(i, j));
                    BG[R(id(i, j))].push_back(id(i, j));
                } else
                    exit(-1);
            }
        }
        Solve();
    }
    

    先写一个读入这个奇怪的图的程序,然后到我的模板库里面复制一份基环树遍历的算法,由于这里只需要知道基环树的大小,那么只注意“incircle”标记的节点就可以了。注意并不是每次dfs都可以找到一棵新的基环树,有可能这棵基环树被前面的dfs找到过,这个就不细讲了。总而言之没有基环树dp就都还算简单。

  • 相关阅读:
    ios6.0,程序为横屏,出现闪退
    [ios]objective-c中Category类别(扩展类)专题总结
    iOS Dev (26) 初步了解下UIColor的最常用知识
    CGGeometry.h详解
    ipa验证错误问题总结
    UITableView和UITableViewCell的几种样式
    willRotateToInterfaceOrientation 屏幕旋转
    ios 使用第三方框架注意
    automaticallyAdjustsScrollViewInsets 使用
    contentSize、contentInset和contentOffset区别
  • 原文地址:https://www.cnblogs.com/KisekiPurin2019/p/12695444.html
Copyright © 2020-2023  润新知