Codeforces Round #660 (Div. 2)

Codeforces Round #660 (Div. 2)

A. Captain Flint and Crew Recruitment

题意: 给定T个测试样例,每个测试样例给定1个数字n,问n是否能够分成4个不同的数字,4个数字中near prime的个数大于等于3。定义near prime为:两个素数p和q的乘积,且p < q。如果能的话输出YES,下一行输出那4个数字;不能输出NO。
题解: 由于需要分成4个near prime。而最小的3个near prime为:36、40、44。因此只需要分成6、10、14和n-30。由于要4个数字不同,因此需要特判36、40、44的情况。
代码:

#include <bits/stdc++.h>

using namespace std;

int main() {
    int n;
    cin >> n;
    for (int i = 1, t; i <= n; ++i) {
        cin >> t;
        if (t < 31) {
            cout << "NO
";
            continue;
        }
        else {
            cout << "YES
";
            if (t == 36) {
                cout << 6 << " " << 10 << " " << 15 << " " << 5 << endl;
                continue;
            }
            else if (t == 40) {
                cout << 6 << " " << 10 << " " << 15 << " " << 9 << endl;
                continue;
            }
            else if (t == 44) {
                cout << 6 << " " << 7 << " " << 10 << " " << 21 << endl;
                continue;
            }
            else {
                cout << 6 << " " << 10 << " " << 14 << " " << t - 30 << endl;
                continue;
            }
        }
    }
    return 0;
}

B. Captain Flint and a Long Voyage

题意: 给定T个测试样例,每个测试样例给定一个n,要求输出一个n位数字。要求输出的n位数字的产生规则如下:将n位数字的每一位变成二进制形式,连接在一起,然后删除最后n个01数字,要求最后剩下的二进制字符串最大,且在不影响答案的前提下,这个n位数字最小。
题解: 由于要然这个n位数字最大,因此要让二进制数字尽可能长,因此选择1001或1000,在没有被删除尾数的情况下,尽可能选择1001。然后因为要删除尾数,所以如果被删除的情况下,1001和1000结果一样,为了尽可能小,选择1000.因此发现:n在1 ~ 4情况下,最后一个为8,前面的为9;在5 ~ 8情况下,最后两个为8,前面为9。(因为每4个一组,会让8和9没有区别,所以只要看有几个4组即可,而且通过分析知道是向上取整的)。
代码:

#include<bits/stdc++.h>

using namespace std;

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        double n;
        cin>>n;
        int limit = ceil(n/4);
        for(int i = 0; i < n - limit; i++) printf("9");
        for(int i = 1; i <= limit; i++) printf("8");
        
        cout<<endl;
    }
    return 0;
}

C. Uncle Bogdan and Country Happiness

题意: 现在有一颗树,根为1。树上有m个人,白天的时候这m个人都在1号点工作,晚上回家。这m个人心情可能会在回家的路上变坏。现在给定每个节点好心情-坏心情的人数,且心情只能从好变为坏,问给出的每个节点的好心情-坏心情的人数是否能够成立,能够成立输出YES,不能成立输出NO。第一行给出测试样例数目T,每个测试样例给出n和m。下一行给出n个数字,如果是0表示该点是一个人的家。下一行给出n个数字,表示每个节点的好心情-不好心情人数。下面n-1行给出树的连边关系。(sum_{}n) <= 10^5^、(sum_{}m) <= 10^5^
题解: 由于心情只能从好变为坏,因此父节点的好心情人数一定大于等于子节点的好心情人数和。所以可以通过sz[u]和h[u]计算出u节点的好心情人数g[u]和坏心情人数b[u],然后判断子节点好心情人数和和g[u]的关系即可。
代码:

#include <bits/stdc++.h>

using namespace std;

int T, n, m;
int const N = 2e5 + 10;
int g[N], b[N], h[N], p[N], sz[N];
int e[N * 2], ne[N * 2], hh[N], idx;
int flg;

void add(int a, int b) {
    e[idx] = b, ne[idx] = hh[a], hh[a] = idx++;
}

void dfs(int u, int fa) {
    sz[u] = p[u];
    int G = 0;
    for (int i = hh[u]; ~i; i = ne[i]) {
        int j = e[i];
        if (j == fa) continue;
        dfs(j, u);
        sz[u] += sz[j];
        G += g[j];
    }
    
    g[u] = (sz[u] + h[u]) / 2, b[u] = (sz[u] - h[u]) / 2;
    if (g[u] + b[u] != sz[u] || g[u] < 0 || b[u] < 0 || g[u] < G || g[u] - b[u] != h[u]) flg = 0;
    return ;
}

int main() {
    cin >> T;
    while (T--) {
        memset(sz, 0, sizeof sz);
        memset(hh, -1, sizeof h);
        idx = 0;
        flg = 1;
        cin >> n >> m;
        for (int i = 1; i <= n; ++i) scanf("%d", &p[i]);
        for (int i = 1; i <= n; ++i) scanf("%d", &h[i]);
        for (int i = 1, a, b; i <= n - 1; ++i) {
            scanf("%d%d", &a, &b);
            add(a, b);
            add(b, a);
        }
        dfs(1, -1);
        if (flg) cout << "YES
";
        else cout << "NO
";
    }
    return 0;
}
原文地址:https://www.cnblogs.com/spciay/p/13414716.html