Codeforces Round #660 (Div. 2)A~D

总结一下:菜是原罪。菜哭。

A. Captain Flint and Crew Recruitment

题意:

给你个n,让你把他拆分成4个数。其中至少三个数是伪素数。伪素数的定义是:两个素数的乘积。如:6 = 2 × 3,10 = 2 × 5。坑点:这四个数互不相等。

题解:

我们从小到大写几个伪素数:6、10、14、15、21…
最小为6+10+14 + 1 = 31。
所以n < 31,无解。
n >= 31 时,这时候要特判,36、40、44,n-30=6 or 10 or 14时,这时候你自己找一下就行了。

ACcode:

/*
 * @Author: NEFU_马家沟老三
 * @LastEditTime: 2020-07-31 15:13:58
 * @CSDN blog: https://blog.csdn.net/acm_durante
 * @E-mail: [email protected]
 * @ProbTitle: 
 */
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define lowbit(x) ((x) & -(x))
#define mem(a, b) memset(a, b, sizeof(a))
const double PI = acos(-1.0);
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        if (n < 31 )
            cout << "NO\n";
        else
        {
            cout << "YES\n";
            if(n == 40)
                cout << 6 << ' ' << 10 << ' ' << 21 << ' ' << 3 << endl;
            else if (n == 44)
                cout << 6 << ' ' << 7 << ' ' << 10 << ' ' << 21 << endl;
            else if (n == 36)
                cout << 5 << ' ' << 6 << ' ' << 10 << ' ' << 15 << endl;
            else
                cout << 14 << ' ' << 10 << ' ' << 6 << ' ' << n - 30 << endl;
        }
    }
    return 0;
}

B. Captain Flint and a Long Voyage

题意:

给你个n,表示有n位数。将其每一位用二进制表示。如 x = 729,则k = 111 10 1001。现在将二进制表示的k的后n位擦去得到r,使r数最大。
若得到的数一样大,则输出x较小的内个。

题解:

我们首先只能从8、9中选取,因为这样得到的数最大。
8 : 1000、9 : 1001。
我们剩下的就是找规律:
n = 1 : x = 8 : k = 1000 : r = 100
n = 2 : x = 98 : k = 1001 1000 : r = 1001 10
n = 3 : x = 998 : k = 1001 1001 1000 : r = 1001 1001 1
n = 4 : x = 9998 :k = 1001 1001 1001 1000 : r = 1001 1001 1001
n = 5 : x = 99988 : k = 1001 1001 1001 1000 1000 : r = 1001 1001 1001 100

每4次是一次循环,8的个数是n/4向上取整。

/*
 * @Author: NEFU_马家沟老三
 * @LastEditTime: 2020-07-31 15:40:32
 * @CSDN blog: https://blog.csdn.net/acm_durante
 * @E-mail: [email protected]
 * @ProbTitle: 
 */
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define lowbit(x) ((x) & -(x))
#define mem(a, b) memset(a, b, sizeof(a))
const double PI = acos(-1.0);
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        int cnt_8 = (n + 3) / 4;
        rep(i,1,n-cnt_8) cout << 9;
        rep(i,1,cnt_8) cout << 8;
        cout << endl;
    }
    return 0;
}

C. Uncle Bogdan and Country Happiness

题意:

一开始所有人都在城市1,然后每个人通过最短路回到自己的家,在回家的途中好心情可能会变差,但是坏心情不能变好。每个城市都有个心情测试器:他的数值h是 途经当前城市的人中 好心情的人数 - 坏心情的人数。
当每个人都回到家后,问你每个城市的心情测试器 测试的是否准确。当全部准确话输出“YES”,否则输出“NO”。

题解:

h = good - bad。
peoole = good + bad。
我们能得出good = ( h + people ) / 2
我们从城市1开始dfs树遍历,在遍历的时候通过上述公式计算出当前城市心情好的人数。分下列三种情况:

  1. people + h 不能被 2 整除,则NO
  2. 计算出的good满足:0<= good <= people
  3. 用公式计算出的good的人数 >= 子树心情好的人数
    第三条:因为我们是递归向根传值,所以在这个逆向过程中,原本坏心情可以变成好心情。

ACcode:

/*
 * @Author: NEFU_马家沟老三
 * @LastEditTime: 2020-07-31 14:12:34
 * @CSDN blog: https://blog.csdn.net/acm_durante
 * @E-mail: [email protected]
 * @ProbTitle: dfs树遍历(补题)
 */ 
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define lowbit(x) ((x) & -(x))
#define mem(a, b) memset(a, b, sizeof(a))
const double PI = acos(-1.0);
const ll mod = 1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
int t,n,m;
const int N = 2e5+5;
struct edge 
{
    int to,next;
}e[N];
int cnt;
int peo[100050],h[100050];
int pp[100050],good[100050];
int head[100050];
void add(int u,int v){
    e[++cnt].to = v;
    e[cnt].next = head[u];
    head[u] = cnt;
}
bool flag = 0;

void dfs(int now,int pre){
    if(flag) return;
    pp[now] = peo[now];
    int sum_g = 0;
    for(int i = head[now]; ~i ; i = e[i].next){
        if(pre == e[i].to) continue;
        dfs(e[i].to,now);
        sum_g += good[e[i].to];
        pp[now] += pp[e[i].to];
    }
    if((pp[now]+h[now])%2){ flag = 1;return;}
    good[now] = (pp[now]+h[now]) >> 1;
    if(good[now]<0||pp[now]<good[now]) {flag = 1;return;}
    if(sum_g > good[now]) {flag = 1;return;} 
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin >> t;
    while (t--)
    {
        mem(head,-1),mem(e,0);
        cnt = 0;
        flag = 0;
        cin >> n >> m;
        rep(i,1,n) cin >> peo[i];
        rep(i,1,n) cin >> h[i];
        rep(i,1,n-1){
            int x,y;
            cin >> x >> y;
            add(x,y),add(y,x);
        }
        dfs(1,-1);
        cout << (flag?"NO":"YES") << endl;
    }
    
    return 0;
}

D. Captain Flint and Treasure

题意:

给你两个长度为n的序列a,b。
我们总共进行n次下列操作:

  1. 选择 位置 i
  2. 将 a[i] 加到 ans上
  3. 如果 b[i] != -1 ,则将 a[i] 加到 a[bi]上
    输出ans的最大值和n次操作的顺序。

题解

我们根据b数组进行建树,如果b[i] != -1,则我们从 b[i] 到 i 建立一个有向边。
我们对每一课树进行遍历,并建立两个数组存放操作顺序。
如果a[i] >=0,我们则优先进行这次的操作存入到数组1中,因为他对他的根节点是做正贡献。
若a[i] < 0,我们则将这次操作放到根节点的后面,存放到数组2中,因为如果将他加到根节点的话,他做的是负贡献。最后将数组二倒序输出。

ACcode:

/*
 * @Author: NEFU_马家沟老三
 * @LastEditTime: 2020-07-31 16:17:45
 * @CSDN blog: https://blog.csdn.net/acm_durante
 * @E-mail: [email protected]
 * @ProbTitle: dfs树遍历(补题)
 */ 
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define lowbit(x) ((x) & -(x))
#define mem(a, b) memset(a, b, sizeof(a))
const double PI = acos(-1.0);
const ll mod = 1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N = 2e5+5;
ll a[N],b[N];
int cnt = 0;
struct Edge
{
    int to,next;
}e[N];
int head[N];
void add(int u,int v){
    e[++cnt].to = v;
    e[cnt].next = head[u];
    head[u] = cnt;
}
ll ans = 0;
vector<int>orede[2];
bool vis[N];

void dfs(int pos){
    vis[pos] = 1;
    for(int i = head[pos];~i;i = e[i].next){
        if(!vis[e[i].to])
            dfs(e[i].to);
    }
    ans+=a[pos];
    if(a[pos]>0&&b[pos]!=-1)
        a[b[pos]] += a[pos];
    if(a[pos] > 0) orede[0].push_back(pos);
    else orede[1].push_back(pos);
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int n;
    mem(head,-1);
    cin >> n;
    rep(i,1,n) cin >> a[i];
    rep(i,1,n) {
        int x;
        cin >> x;
        if(x!=-1)
            add(x,i);
        b[i] = x;
    }
    rep(i,1,n){
        if(vis[i]) continue;
        dfs(i);
    }
    cout << ans << endl;
    reverse(orede[1].begin(),orede[1].end());
    for(auto &i : orede[0]) cout << i << ' ';
    for(auto &i : orede[1]) cout << i << ' ';
    cout << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/acm_durante/article/details/107713791