A. Captain Flint and Crew Recruitment(签到) 

题意:定义可以分解成两个不同素数相乘的数为nearly prime,将一个数分解为4个不同的数,其中至少有三个nearly prime

开始没注意到4个不同的数,wa了

最小的四个nearly prime:6 10 14 15,<= 30的数无法分解,特别地 36 = 6 + 10 + 15 + 5,40 = 6 + 10 + 15 + 9,44 = 6 + 10 + 15 + 13,其他的都是6 + 10 + 14 + (n - 30)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;

int main()
{
    int t, n;
    scanf("%d", &t);
    while(t--) {
        scanf("%d", &n);
        if(n <= 30)
            cout<<"NO"<<'\n';
        else {
            cout<<"YES"<<'\n';
            if(n == 36)
                cout<<"6 10 15 5"<<'\n';
            else if(n == 40)
                cout<<"6 10 15 9"<<'\n';
            else if(n == 44)
                cout<<"6 10 15 13"<<'\n';
            else
                cout<<"6 10 14 "<<n - 30<<'\n';
        }
    }
    return 0;
}

B. Captain Flint and a Long Voyage(找规律)

 

题意: 找到使r取最大值的最小的x。r = 将x按位写成二进制的形式,擦掉后x位形成的数(当作10进制看)

打表发现的。。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 75;

int main()
{
    int t, n;
    scanf("%d", &t);
    while(t--) {
        scanf("%d", &n);
        int b = (n + 3) / 4;
        int a = n - b;
        for(int i = 1; i <= a; ++i) cout<<'9';
        for(int i = 1; i <= b; ++i) cout<<'8';
        cout<<'\n';
    }
    return 0;
}

C. Uncle Bogdan and Country Happiness(树 + dfs)

题意: 

有n个城市,共m个人,给出每个城市的居民数,起初所有人都在城市1工作,都是开心的,在回家的过程中可能变得不开心,每个城市的快乐值 = 经过该点快乐的人数 - 经过该点不快乐的人数。

思路:

来自https://blog.csdn.net/ljw_study_in_CSDN/article/details/107711221

设sum[i]表示经过i点的总人数,good[i]表示经过i点是好心情的人数,bad[i]表示经过i点是坏心情的人数。
那么有:sum[i]=good[i]+bad[i], h[i]=good[i]-bad[i]。
消去bad[i]得到:good[i]=(sum[i]+h[i])/2
其中,h[i]已知,sum[i]实际上就是家在 i 的子树节点(包括i)的人数,在dfs回溯的时候即可求出。那么good[i]也可求出了。

然后,考虑good[i]的限制条件:

  1. good[i]必须为整数,那么 sum[i]+h[i] 为偶数。
  2. 0<=good[i]<=sum[i]。
  3. good[v1]+good[v2]+…+good[vk]<=good[i],其中v1,v2,…,vk为 i 的子树节点(不包括i)。因为从 i 点往下走其子树节点的过程中,好心情的总人数会降低或者不变,所以经过 i 的子树节点的好心情总人数小于等于经过 i 的好心情人数。

只要满足上述三条限制条件则存在可能性。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
vector<int>g[N];
int h[N], p[N], sum[N], good[N];
bool flag;

void dfs(int u, int fa) {
    if(!flag) return ;
    sum[u] = p[u];
    int s = 0;
    for(int v : g[u]) {
        if(v == fa) continue;
        dfs(v, u);
        if(!flag)
            return ;
        sum[u] += sum[v];
        s += good[v];
    }
    int tmp = h[u] + sum[u];
    if(tmp & 1) {
        flag = 0;
        return ;
    }
    good[u] = tmp / 2;
    if(good[u] < 0 || good[u] > sum[u] || s > good[u]) {
        flag = 0;
        return ;
    }
}

int main()
{
    int t, n, m, u, v;
    scanf("%d", &t);
    while(t--) {
        scanf("%d%d", &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; i <= n; ++i)
            g[i].clear();
        for(int i = 1; i < n; ++i) {
            scanf("%d%d", &u, &v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        flag = 1;
        dfs(1, 0);
        if(flag) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

 D. Captain Flint and Treasure(思维 + 拓扑排序)

题意:每次选择包括两个步骤:ans += a[i],a[b[i]] += a[i],构造一个选择顺序使ans最大

思路:a[b[i]] += a[i]可以看作一条从a[i]到a[b[i]]的有向边,如果a[i] > 0,这条边会使a[b[i]]变大,是有利的,这时a[i]应尽早取,否则是不利的,a[i]应靠后取。跑一边拓扑排序,按拓扑序列把正值和负值分开存储,正值正序输出,负值逆序输出(靠前的会导致后面更多的数变小)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;

ll a[N], b[N], in[N], n, ans;
vector<int>x, y;

void topo() {
    x.clear();
    y.clear();
    queue<int>q;
    for(int i = 1; i <= n; ++i) {
        if(in[i] == 0)
            q.push(i);
    }
    while(q.size()) {
        int tmp = q.front();
        q.pop();
        int v = b[tmp];
        if(v != -1) {
            in[v]--;
            if(in[v] == 0) q.push(v);
            if(a[tmp] > 0) a[v] += a[tmp];
        }
        ans += a[tmp];
        if(a[tmp] >= 0) x.push_back(tmp);
        else y.push_back(tmp);
    }
}

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) in[i] = 0;
    for(int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
    for(int i = 1; i <= n; ++i) {
        scanf("%lld", &b[i]);
        if(b[i] != -1) in[b[i]]++;
    }
    ans = 0;
    topo();
    printf("%lld\n", ans);
    int xs = x.size(), ys = y.size();
    for(int i = 0; i < xs; ++i) {
        if(i > 0) printf(" ");
        printf("%d", x[i]);
    }
    for(int i = ys - 1; i >= 0; --i)
        printf(" %d", y[i]);
    printf("\n");
    return 0;
}