牛客刷题-Day17

牛客刷题-Day17

今日刷题:\(1021-1028\)

1022 经商

题目描述

小d是一个搞房地产的土豪。每个人经商都有每个人经商的手段,当然人际关系是需要放在首位的。

小d每一个月都需要列出来一个人际关系表,表示他们搞房地产的人的一个人际关系网,但是他的精力有限,对应他只能和能够接触到的人交际。比如 \(1\) 认识 \(2\)\(2\) 认识 \(3\),那么 \(1\) 就可以接触 \(3\) 进行交际,当然 \(1\)\(2\) 也可以交际。

小d还很精明,他知道他和谁交际的深获得的利益大,接下来他根据自己的想法又列出来一个利益表,表示他和这些人交际需要耗用多少精力,能够获得的利益值为多少。

小d想知道,他在精力范围内,能够获得的利益值到底是多少。

设定小d自己的编号为 \(1\)。并且对应一个人的交际次数限定为 \(1\)

输入描述

本题包含多组输入,第一行输入一个数 \(t\),表示测试数据的组数。
每组数据的第一行输入三个数,\(N\)\(M\)\(C\),表示这个人际关系网一共有多少个人,关系网的关系数,以及小d的精力值。
接下来 \(N-1\) 行,每行两个数 \(a_i\)\(b_i\)。这里第 \(i\) 行表示和编号为 \(i+1\) 的人交际需要花费 \(a_i\) 的精力,能够获得的利益值为 \(b_i\)
再接下来 \(M\) 行,每行两个数 \(x\)\(y\),表示编号为 \(x\) 的人能够和编号为 \(y\) 的人接触。

\(t<=50,2<=N<=10000,1<=M<=10*N,1<=a_i,b_i<=10,1<=C<=500,1<=x,y<=N\)

输出描述

输出包含一行,表示小d能够获得的最大利益值。

示例

输入

1
5 3 7
5 10
3 2
4 3
1 100
1 2
2 3
1 4

输出

10

解题思路

并查集维护关系网,\(01\) 背包求解最大利益值。

C++ 代码

#include <bits/stdc++.h>
using namespace std;
const int N = 10010, M = 510;

int t;
int p[N], a[N], b[N], f[M];

int find(int x) {
    if (p[x] != x)
        p[x] = find(p[x]);
    return p[x];
}

int main() {
    scanf("%d", &t);
    while (t--) {
        memset(p, 0, sizeof p);
        memset(a, 0, sizeof a);
        memset(b, 0, sizeof b);
        memset(f, 0, sizeof f);
        int n, m, c;
        scanf("%d%d%d", &n, &m, &c);
        for (int i = 1; i <= n; i++)
            p[i] = i;
        for (int i = 2; i <= n; i++)
            scanf("%d%d", &a[i], &b[i]);
        while (m--) {
            int x, y;
            scanf("%d%d", &x, &y);
            p[find(x)] = find(y);
        }
        for (int i = 2; i <= n; i++)
            if (find(1) == find(i))
                for (int j = c; j >= a[i]; j--)
                    f[j] = max(f[j], f[j - a[i]] + b[i]);
        printf("%d\n", f[c]);
    }
    return 0;
}

1023 [USACO 2011 Ope S]Learning Languages

题目描述

Farmer John's \(N\) (\(2 <= N <= 10,000\)) cows, conveniently numbered \(1...N\), are fluent in some \(M\) (\(1 <= M <= 30,000\)) languages, also conveniently numbered from \(1...M\). Cow \(i\) can speak in \(K_i\) (\(1 <= K_i <= M\)) languages, namely \(L_{i_1},L_{i_2},...,L_{i_{K_i}}\) (\(1 <= L_{i_j} <= M\)). FJ's cows aren't THAT smart, so the sum of \(K_i\) over all cows i is at most \(100,000\).
Two cows can't directly talk to each other unless both speak a common language. However, cows can pass messages along, translating if necessary. In other words, cows \(A\) and \(B\) can have a conversation if and only if there exists a sequence of cows \(T_1,T_2,...,T_k\) such that \(A\) and \(T_1\) share a language, \(T_1\) and \(T_2\) share a language, etc., and \(T_k\) and \(B\) share a language.
Farmer John wishes that his cows could be even more social, so he wants all his cows to be able to socialize with any other cow. He can buy books to teach any one of his cows any language he pleases. Being a fairly frugal farmer, FJ wants to purchase the minimum number of books necessary to enable all of his cows to speak to each other. Help him determine:

  • The minimum number of books he must purchase
  • Any set of books assigned to cows in any order which will help him meet this goal; a program will grade your output.

By way of example, suppose there are three cows named Alberta, Bessie, and Contessa along with three languages denoted as #1, #2, and #3. Alberta can speak languages #2 and #3, Bessie can speak language #2, and Contessa can speak language #1. Currently, Alberta and Bessie can talk to each other, but Contessa is left alone.

#1 #2 #3
Alberta x x
Bessie x
Contessa x

FJ wants to fix this situation, so he can buy Contessa a book to teach her language #2. This will ensure all cows speak the same language, so they can all communicate with one another.
Note that an alternate solution exists: instead, FJ could buy
Contessa a book to teach her language #3. Not all cows would speak the same language, but this would still be a valid solution because Contessa could communicate through Alberta (who also speaks language #3) if she wants to talk to Bessie. Other alternatives exist, and any valid alternate solution will also be accepted.

输入描述

  • Line \(1\): Two space-separated integers: \(N\) and \(M\).
  • Lines \(2...N+1\): Line \(i+1\) describes the languages that cow \(i\) can speak with \(K_i+1\) space-separated integers: \(K_i,L_{i_1},L_{i_2},...,L_{i_{K_i}}\).

输出描述

  • Line \(1\): \(A\) single integer that is the minimum number of books that FJ must purchase.
  • Lines \(2...B+1\): Line \(i+1\) contains two space-separated integers: the language id # and the id # of the cow to receive book \(i\). If multiple solutions exist, print any one.
示例

输入

3 3 
2 3 2 
1 2 
1 1

输出

1

解题思路

并查集。\(language\) 数组维护语言的占用情况,\(language_i=j\) 表示 \(i\) 语言被牛 \(j\) 所使用。这样每次新来一个牛,对于其所会的语言,如果已被其他牛掌握,二者可以交流,可以少用一本书。

C++ 代码

#include <bits/stdc++.h>
using namespace std;
const int N = 30010;

int n, m;
int p[N], language[N];

int find(int x) {
    if (p[x] != x)
        p[x] = find(p[x]);
    return p[x];
}

void merge(int x, int y) {
    int px = find(x), py = find(y);
    p[px] = py;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        p[i] = i;
    int ans = n - 1;
    for (int i = 1; i <= n; i++) {
        int k;
        scanf("%d", &k);
        while (k--) {
            int l;
            scanf("%d", &l);
            if (language[l]) { // 该语言也其他牛被掌握
                if (find(i) != find(language[l])) {
                    merge(i, language[l]);
                    ans--;
                }
            } else {
                language[l] = i;
            }
        }
    }
    printf("%d\n", ans);
    return 0;
}

1026 小C的周末

题目描述

愉快的周末到了,小C和他的 \(N-1\) 个朋友买了 \(M\) 个游戏,游戏编号从 \(1~M\)。每个游戏都是多人游戏,他们打算周末一起打游戏。
小C的每个朋友都决定好了要玩哪一款游戏(会有一组人打同一款游戏),并且每人手上都有一台游戏机,这种游戏机可以通过特定的游戏机连接线连接起来。
但是,他们面临着一个问题:目前没有一个朋友的游戏机是互相连接的。所以它们必须用可用的游戏机连接线连接起来。小C决定依次使用第 \(i\) 条连接线把他的朋友 \(u_i\)\(v_i\) 的游戏机连接起来。也就是说,假设有 \(Q\) 条连接线,小C只能先使用第一条,然后使用第二条,然后使用第三条...最后使用第 \(Q\) 条。
一个游戏能开始的条件是所有玩这个游戏的朋友的游戏机都被连接起来(如果不是直接连接的话,那么就必须存在一条连接它们的路径)。他们希望尽快开始比赛。
在每个游戏中,找出在添加了第几条连接线之后能开始游戏。如果在一个游戏中只有一个人玩,则输出 \(0\)(因为他立马可以开始游戏)。如果不存在,则输出 \(-1\)

输入描述

多组输入
第一行包含三个整数 \(N\)\(M\)\(Q\)
第二行给 \(N\) 个用空格分隔的整数,第 \(i\) 个整数代表第 \(i\) 个朋友想玩的游戏。
接下来的 \(Q\) 行,每行两个整数 \((u, v)\),代表电线 \(i\) 连接的两个人的电脑。
\(1 <= N, M <= 10^5,0 <= Q <= 10^5\)

输出描述

对于每个游戏,输出一个整数,表示添加了第几条连接线之后能开始游戏,每行以换行符结束

示例

输入

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

输出

3
4

说明:第一个游戏有两个人参加(\(1\)\(5\)),在添加了第三条电线之后他们电脑互相连接;第二个游戏三个人参加(\(2\)\(3\)\(4\)),在添加第四条电线之后他们电脑互相连接。

解题思路

并查集。统计每个游戏有多少人参加。添加电线即执行合并操作,同时统计当前所有游戏的参加情况,如果参加人数和最初的统计相同,则可以开始。具体可以参考代码理解。

C++ 代码

#include <bits/stdc++.h>
using namespace std;
const int N = 100010;

int n, m, q;
int p[N], cnt[N];
int res[N];
map<int, int> s[N]; // s[i][j] 表示以 i 为根游戏 j 的人数

void init(int n) {
    memset(res, -1, sizeof res);
    memset(cnt, 0, sizeof cnt);
    for (int i = 1; i <= n; i++) {
        p[i] = i;
        s[i].clear();
    }
}

int find(int x) {
    if (p[x] != x)
        p[x] = find(p[x]);
    return p[x];
}

int main() {
    while (~scanf("%d%d%d", &n, &m, &q)) {
        init(n);
        for (int i = 1; i <= n; i++) {
            int x;
            scanf("%d", &x);
            cnt[x]++;
            s[i][x] = 1;
        }
        for (int t = 1; t <= q; t++) {
            int u, v;
            scanf("%d%d", &u, &v);
            int pu = find(u), pv = find(v);
            if (pu == pv)
                continue;
            if (s[pu].size() > s[pv].size())
                swap(pu, pv);
            p[pu] = pv;
            for (auto [i, j]: s[pu]) {
                s[pv][i] += j;
                if (s[pv][i] == cnt[i])
                    res[i] = t;
            }
        }
        for (int i = 1; i <= m; i++) {
            if (cnt[i] <= 1)
                printf("%d\n", cnt[i] - 1);
            else
                printf("%d\n", res[i]);
        }
    }
    return 0;
}

1028 Parity game

题目描述

Now and then you play the following game with your friend. Your friend writes down a sequence consisting of zeroes and ones. You choose a continuous subsequence (for example the subsequence from the third to the fifth digit inclusively) and ask him, whether this subsequence contains even or odd number of ones. Your friend answers your question and you can ask him about another subsequence and so on. Your task is to guess the entire sequence of numbers.
You suspect some of your friend's answers may not be correct and you want to convict him of falsehood. Thus you have decided to write a program to help you in this matter. The program will receive a series of your questions together with the answers you have received from your friend. The aim of this program is to find the first answer which is provably wrong, i.e. that there exists a sequence satisfying answers to all the previous questions, but no such sequence satisfies this answer.

输入描述

The first line of input contains one number, which is the length of the sequence of zeroes and ones. This length is less or equal to \(1000000000\). In the second line, there is one positive integer which is the number of questions asked and answers to them. The number of questions and answers is less or equal to \(5000\). The remaining lines specify questions and answers. Each line contains one question and the answer to this question: two integers (the position of the first and last digit in the chosen subsequence) and one word which is either even or odd (the answer, i.e. the parity of the number of ones in the chosen subsequence, where even means an even number of ones and odd means an odd number).

输出描述

There is only one line in output containing one integer \(X\). Number \(X\) says that there exists a sequence of zeroes and ones satisfying first \(X\) parity conditions, but there exists none satisfying \(X+1\) conditions. If there exists a sequence of zeroes and ones satisfying all the given conditions, then number \(X\) should be the number of all the questions asked.

示例

输入

10
5
1 2 even
3 4 odd
5 6 even
1 6 even
7 10 odd

输出

3

解题思路

并查集。根据条件维护关系,直至发生矛盾。
这里给的一个区间内的 \(1\) 的个数为奇数或者偶数,那么就可以转换成序列 \([1,l-1]\)\([1,r]\) 的差值为奇数或者偶数,进而转换为前缀和 \(s_{l-1}\)\(s_r\) 的奇偶性是否相同。那么就可以维护与 \(i\) 奇偶性相同及不同的 \(j\)
\(p_i\) 表示与前缀和 \(s_i\) 奇偶性相同,\(p_{i+n}\) 表示奇偶性不同。
如果当前回答是 even,则说明 \(s_{l-1}\)\(s_r\) 的奇偶性相同,如果 \(p_{l-1}=p_{r+n}\),则说明 \(s_{l-1}\)\(s_r\) 奇偶性不同,矛盾;否则就进行合并操作,进行下一个回答的处理。

因为 \(p_{l-1}\) 表示与 \(s_{l-1}\) 奇偶性相同 \(p_{r+n}\) 表示与 \(s_r\) 奇偶性不同,而 \(s_{l-1}\)\(s_r\) 在回答中奇偶性相同。

C++ 代码

#include <bits/stdc++.h>
using namespace std;
const int N = 10010;

struct S {
    int l, r, v;
};
deque<S> q;
int n, m, ind, ans;
int p[N], dis[N]; // p[i] 表示奇偶性相同 p[i + n] 表示奇偶性不同

void discrete() {
    sort(dis + 1, dis + 1 + ind);
    ind = unique(dis + 1, dis + 1 + ind) - dis - 1;
}

int query(int x) {
    return lower_bound(dis + 1, dis + 1 + ind, x) - dis;
}

int find(int x) {
    if (p[x] == x) 
        return x; 
    return p[x] = find(p[x]);
}

void merge(int x, int y) {
    p[find(y)] = p[find(x)];
}

int main() {
    cin >> n >> m;
    ans = m;
    for(int i = 1; i <= m; i++) {
        int a, b;
        string c;
        cin >> a >> b >> c;
        a--;
        q.push_back({a, b, c == "even" ? 1 : -1});
        dis[++ind] = a, dis[++ind] = b;
    }
    discrete();
    for(int i = 1; i <= ind * 2; i++) p[i] = i;
    while (!q.empty()) {
        S cur = q.front();
        q.pop_front();
        int x = query(cur.l), y = query(cur.r), z = cur.v;
        if (z == -1) {
            if (find(x) == find(y)) {
                ans = m - q.size() - 1;
                break;
            }
            merge(y, x + ind), merge(x , y + ind);
        } else {
            if (find(x) == find(y + ind)) {
                ans = m - q.size() - 1;
                break;
            }
            merge(x, y), merge(x + ind, y + ind);
        }
    }
    cout << ans << endl;
    return 0;
}
posted @ 2025-10-22 15:42  Cocoicobird  阅读(4)  评论(0)    收藏  举报