[Codeforces Round #660 (Div. 2)]1388

6 篇文章 0 订阅
2 篇文章 0 订阅



竞赛首页 Codeforces Round #660 (Div. 2)

A - Captain Flint and Crew Recruitment [思维]

题意

定义近似质数为 x = p × q x = p \times q x=p×q p , q p, q p,q 均为质数
问整数 n n n 是否可以由 4 4 4 个不同的整数相加得到,且其中的 3 3 3 个整数要为近似质数

分析

首先最小的四个近似质数的数为 6 , 10 , 14 , 15 6, 10, 14, 15 6,10,14,15
则和不大于 6 + 10 + 14 6+10+14 6+10+14 的数必然无解,其他都是有解的
如果 x = n − 6 − 10 − 14 x = n - 6 - 10 - 14 x=n61014 x x x 等于 6 , 10 , 14 6,10,14 6,10,14 其中的一个数,那么就令第三个数为 15 15 15,最后一个数即 x − 1 x-1 x1
这样是可以保证不会还有一样的情况

代码

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

int main(){
    int T;
    scanf("%d", &T);
    while(T--) {
        int n;
        scanf("%d", &n);
        int x = n - 6 - 10 - 14;
        if(x <= 0)  puts("NO");
        else{
            puts("YES");
            if(x == 6 || x == 10 || x == 14)
                printf("6 10 15 %d\n", x-1);
            else
                printf("6 10 14 %d\n", x);
        }
    }
    return 0;
}


B - Captain Flint and a Long Voyage [思维]

题意

求一个长度为 n n n 的数字串,每个字符 ′ 1 ′ ≤ s [ i ] ≤ ′ 9 ′ '1' \leq s[i] \leq '9' 1s[i]9
要求这个字符转化为二进制形式,可以由 1 − 9 1 - 9 19 的二进制形式的几个数构成
且删去二进制下最后的 n n n 个字符后,这个数字串尽可能大
如果有多个符合的,则输出原字典序最小的一个

分析

首先考虑的是二进制下字符串长度,显然要使得串越长越越好,那么可以选的数只有 9 = ( 1001 ) 2 , 8 = ( 1000 ) 2 9 = (1001)_2, 8 = (1000)_2 9=(1001)2,8=(1000)2
对于要删去的数,选择为 8 8 8 可以使字典序尽可能小
要使删去后的字符串尽可能大,那么没被删去的就应该为 9 9 9

代码

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
using namespace std;
typedef long long ll;
const int inf = 2e9 + 5;
const int maxn = 40 + 5;
typedef long long ll;

int main() {
    int T, n;
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        int m = (n + 3) / 4;
        for(int i = n; i > m; --i) putchar('9');
        for(int i = m; i > 0; --i) putchar('8');
        puts("");
    }
    return 0;
}


C - Uncle Bogdan and Country Happiness [dfs] ★★

题意

题目有点长
总共有 n n n 个城市,编号 i i i 的城市住有 p i p_i pi 个人, 1 1 1 是所有人打工的城市
晚上打工的人要从 1 1 1 回家,每个人都有一个开心值,在回去的路上开心值可以保持不变或者降低
即开心值可以为 1 1 1 或者 − 1 -1 1,如果为 − 1 -1 1 则不能再增加为 1 1 1,但是为 1 1 1 的可以降低为 − 1 -1 1
h i h_i hi 表示回家路上经过编号为 i i i 的城市的人开心值总和
h h h 序列是否是可以满足的

分析

每个城市需要满足的就是
c n t 1 [ i ] cnt1[i] cnt1[i] 经过城市 i i i是心情好的人数, c n t 0 [ i ] cnt0[i] cnt0[i] 是经过城市 i i i心情不好的人数, n u m num num 是经过这个城市的总人数
c n t 1 [ i ] + c n t 0 [ i ] = n u m [ i ] cnt1[i] + cnt0[i] = num[i] cnt1[i]+cnt0[i]=num[i]
c n t 1 [ i ] − c n t 0 [ i ] = h [ i ] cnt1[i] - cnt0[i] = h[i] cnt1[i]cnt0[i]=h[i]
2 ∗ c n t 1 [ i ] = n u m [ i ] + h [ i ] 2 * cnt1[i] = num[i] + h[i] 2cnt1[i]=num[i]+h[i]
不满足的情况具体可见代码

代码

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
using namespace std;
typedef long long ll;
const int inf = 2e9 + 5;
const int maxn = 1e5 + 5;
typedef long long ll;

vector<int> ed[maxn];
int h[maxn];
int p[maxn];
int num[maxn]; // 总人数
int cnt1[maxn]; // 好心情的人数
bool flag;

void dfs(int u, int fa) {
    int ans = 0; num[u] = p[u];
    for(auto v : ed[u]) {
        if(v == fa) continue;
        dfs(v, u);
        num[u] += num[v], ans += cnt1[v];
    }
    cnt1[u] = (num[u] + h[u]) / 2;
    if(abs(num[u] + h[u])%2 || ans > cnt1[u])   flag = false;
    else if(cnt1[u] < 0 || num[u] < cnt1[u])    flag = false;
}

int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        int n, m;
        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)
            num[i] = cnt1[i] = 0, ed[i].clear();
        for(int i = 1, u, v; i < n; ++i) {
            scanf("%d%d", &u, &v);
            ed[u].push_back(v), ed[v].push_back(u);
        }
        flag = true;
        dfs(1, 0);
        printf("%s\n", flag ? "YES" : "NO");
    }
    return 0;
}


D - Captain Flint and Treasure [拓扑] ★★

题意

给两个长度为 n n n 的数组 a , b a, b a,b
最初 a n s = 0 ans = 0 ans=0
接下来的操作为

  1. 选择一个位置 i ( 1 ≤ i ≤ n ) i (1 \leq i \leq n) i(1in)
  2. a n s + = a i ans += a_i ans+=ai
  3. 如果 b i ≠ − 1 b_i \not= -1 bi=1,则 a b i + = a i a_{b_i} += a_i abi+=ai

对于每个 a [ i ] a[i] a[i],必须且只能选择一次,问如何选择该序列可以使 a n s ans ans 最大

分析

可以画一下最后一个样例
在这里插入图片描述
可以发现,先要进行选择的数应该是度数为 0 0 0 的数
在每一次选择过后,要继续选择的数还是当前度数变为 0 0 0 的数
如果该数可以对他指向的数得到 >0 的贡献,那么就可以排在他指向的数之前
否则,他应该排在他指向的数之后
将无法得到 >0 贡献的数放在另一个数组中存放,表示这些数都是要后面才可以取的
最后再将这些 < 0 贡献的数逆序输出,举个栗子,比如上图的 5(5), 6(-2), 7(-3)
按顺序依次弹入的为 6(-2), 7(-3), 5(5)
显然 5 是不能排在 6, 7 后面的,会降低贡献值,所以要逆序输出

代码

#include <bits/stdc++.h>
#define pii pair<int,int>
#define pll pair<long,long>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
const int maxm = 4e6 + 5;

vector<int> vv[maxn], res[2];
int ind[maxn];
int b[maxn];
ll a[maxn];

void topu(int n) {
    queue<int> q;
    while(!q.empty()) q.pop();
    for(int i = 1; i <= n; ++i) {
        if(ind[i] == 0) q.push(i);
    }
    ll ans = 0;
    while(!q.empty()) {
        int u = q.front(); q.pop();
        ans += a[u];
        res[a[u] >= 0 ? 0 : 1].push_back(u);
        for(auto v : vv[u]) {
            if(a[u] >= 0)   a[v] += a[u];
            ind[v]--;
            if(ind[v] == 0) q.push(v);
        }
    }
    printf("%lld\n", ans);
    for(auto v : res[0])    printf("%d ", v);
    for(int i = (int)res[1].size()-1; i >= 0; --i)
        printf("%d%c", res[1][i], i ? ' ' : '\n');
}

int main(){
    int n;
    scanf("%d", &n);
    memset(ind, 0, sizeof(ind));
    res[1].clear(), res[2].clear();
    for(int i = 1; i <= n; ++i) vv[i].clear();
    for(int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &b[i]);
        if(b[i] != -1)
            ind[b[i]]++, vv[i].push_back(b[i]);
    }
    topu(n);
    return 0;
}


E - Uncle Bogdan and Projections [几何]

题意

分析

代码




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值