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\n", 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就都還算簡單。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM