Codeforces Round #617 (Div. 3)

A. Array with Odd Sum

题目链接:https://codeforces.com/contest/1296/problem/A

题意:

  你任意次将数组中的某个数改为另一个数,问你能否使数组中奇数的个数为奇数

分析:

  不能为奇数的情况只有两种

  ①、数组的所有元素皆为奇数且数组的长度为偶数

  ②、数组中全是偶数

  判断一下是否存在以上两点即可

#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
    int t;
    cin >> t;
    while(t --)
    {
        int n;
        cin >> n;
        int flag = 0 , cnt = 0 ;
        for(int i = 1 ; i <= n ; i ++)
        {
            int x;
            cin >> x;
            if(x & 1)
            cnt ++ , flag = 1;
        }
        if(!flag || (!(cnt & 1) && cnt == n))
        cout << "NO" << '
';
        else cout << "YES" << '
';
    } 
    return 0;
} 

B. Food Buying

题目链接:https://codeforces.com/contest/1296/problem/B

题意:

  你有 N 元钱,每次你花费X元你可以获得X / 10元的返利,问你最多能花费多少元

分析:

  很显然把个位上的数A和N-A拆开,并花费N-A ,再将返利的钱 + A继续拆成个位值和剩下的值再花费直到花光

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main()
{
    int n , t;
    cin >> t;
    while(t --)
    {
        cin >> n;
        ll ans = 0 , now = 0; 
        while(n)
        {
            if(n < 10) {ans += n ; break ;}
            ans += n - n % 10 , now = n % 10 , now += n / 10 , n = now;
        }
        cout << ans << '
';
    }
    return 0;
}

C. Yet Another Walking Robot

题目链接:https://codeforces.com/contest/1296/problem/C

题意:

  给你一个只包含 L , R , U , D 的字符串 , 其中L代表往左移一格,R代表往右移一格,U代表往上移一格,D代表往下移一格

  现在你可以删除该字符串一段连续的区间,使其终点不变,问你最少可以删除的长度(区间)是多少

分析:

  每当我们重复走过一个点的时候,那么从上一次到该点到这一次到该点这之间的路径是作废的,删除这段路径也就不会影响它的终点

  所以每当我们走过一次重复的路径时更新一次答案即可

#include<bits/stdc++.h>
#define int long long
#define inf 0x3f3f3f
using namespace std;
const int N = 2e5 + 10;
char s[N];
map<int , int>cnt;
signed main()
{
    int t;
    cin >> t;
    while(t --)
    {
        cnt.clear();
        int n , sum = 0 , minn = inf , one , two;
        cin >> n >> s + 1;
        cnt[0] = 0;
        for(int i = 1 ; i <= n ; i ++)
        {
            if(s[i] == 'L') sum -- ;
            if(s[i] == 'R') sum ++ ;
            if(s[i] == 'U') sum += inf;
            if(s[i] == 'D') sum -= inf;
            if(cnt.count(sum) && minn > i - cnt[sum] + 1)
            one = cnt[sum] + 1 , two = i , minn = i - cnt[sum] + 1;
            cnt[sum] = i;
        }
        if(minn == inf)
        cout << -1 << '
';
        else cout << one << " " << two << '
';
    }
    return 0;
}

D. Fight with Monsters

题目链接:https://codeforces.com/contest/1296/problem/D

题意:

  你和你的同伴一起闯关

  一共有N关,每关有一个怪。第i关怪的血量为Hi,你的攻击力为A,你的同伴攻击为B

  每关开始由你先攻击怪,再到你同伴攻击怪...反反复复一直到怪的血量小于等于0

  如果怪最终是被你杀死,则你的得分加1,否则你不得分

  现你有K个卡牌,每个卡牌可以使你的同伴停止攻击一回合,即你攻击完后使用卡牌还轮到你攻击

  问你可以获得的最大得分为多少

分析:

  首先我们将每个怪的血量H取模(a+b),其表示在怪被击杀的那一回合前一共剩余了多少血量,记为h,h一共有三种情况

  ①、h == 0,说明该回合就为击杀回合,则我们回到上一回合,即令 h = a + b,那么很显然击杀回合杀死怪的将是你的同伴

  ②、0 < h <= a,说明在击杀回合中先将怪杀死的将是你

  ③、 a < h,说明在击杀回合回合中将怪杀死的将是你的同伴

  我们统计每关你最少需要使用多少张卡牌才能使最终击杀怪的人是你,然后排个序,挨个取即可

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10;
int h[N];
signed main()
{
    int n , a , b , k , cnt = 0;
    cin >> n >> a >> b >> k;
    for(int i = 1 ; i <= n ; i ++)
    {
        cin >> h[i] , h[i] %= (a + b);
        if(h[i] == 0) h[i] = a + b;
    }
    sort(h + 1 , h + 1 + n);
    for(int i = 1 ; i <= n ; i ++)
    {
        if(h[i] <= a) {cnt ++ ; continue ;}
        int tot = (h[i] - a) / a;
        if((h[i] - a) % a) tot ++ ;
        if(k >= tot) cnt ++ , k -= tot;
        else break ; 
    }
    cout << cnt << '
';
    return 0;
} 

E1. String Coloring (easy version)

题目链接:https://codeforces.com/contest/1296/problem/E1

题意:

  给你一个只包含小写字母的字符串,若相邻字符的颜色不一样,则你可以交换

  现你有两种染色剂0和1,问你染完色后是否能使得该字符串通过交换字符串字典序最小

分析:

  因为数据很小,直接暴力。

  对于每个位置,从它的下一位开始遍历,看它的后面是否有比它小的字符,若有,则将其染成与它不同的颜色

  染完后再遍历字符串判断是否有某个位置的字符大于它的下一位且它们颜色相同即可

#include<bits/stdc++.h>
using namespace std;
const int N = 2e2 + 10 ;
int n , flag;
char s[N];
int ans[N] ;
int main()
{
    memset(ans , -1 , sizeof(ans));
    cin >> n >> s + 1;
    for(int i = 1 ; i <= n ; i ++)
    {
        if(ans[i] == -1)  ans[i] = 0 ;
        for(int j = i + 1 ; j <= n ; j ++) if(s[j] < s[i])  ans[j] = 1 - ans[i] ;
    }
    for(int i = 1 ; i <= n ; i ++)
        for(int j = i + 1 ; j <= n ; j ++)
            if(s[i] > s[j] && ans[i] == ans[j])  flag = 1 ;
    if(flag)  return cout << "NO" << '
' , 0 ;
    cout << "YES" << '
';
    for(int i = 1 ; i <= n ; i ++) cout << ans[i] ;
    cout << '
';
    return 0 ;
}

E2. String Coloring (hard version)

题目链接:https://codeforces.com/contest/1296/problem/E2

题意:

  给你一个只包含小写字母的字符串,若相邻字符的颜色不一样,则你可以交换

  你可以对每个字符进行染色,问要使得染完色后可通过交换让字符串字典序最小,至少需要多少染色剂

分析:

  不难发现每个不降序子序列它们的颜色肯定要涂至相同才可以保证染色剂使用的最少

  那么我们就可以暴力给每个不降序染色,直到整个字符串都被染完色(因为只有26个字符,所以不超过几次就会染完,复杂度是完全没问题的)

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int col[N] , n , cnt , c;
char s[N];
signed main()
{
    cin >> n >> s + 1;
    while(cnt < n)
    {
        ++ c;
        char ch = 'a';
        for(int i = 1 ; i <= n ; i ++)
            if(!col[i] && s[i] >= ch)
                cnt ++ , col[i] = c , ch = s[i];
    }
    cout << c << '
';
    for(int i = 1 ; i <= n ; i ++)
    cout << col[i] << " ";
    cout << '
';
    return 0;
}

F. Berland Beauty

题目链接:https://codeforces.com/contest/1296/problem/F

题意:

  给你一颗共有 N 个节点的树,再给你N - 1条边,你不知道这些边的边权

  但是你有 M 条信息,每条信息将告诉你从 U 到 V 的所有边中最小值为 W

  现要求你构造出这N - 1条边的边权

分析: 

  以节点1为树根建树

  我们先对 M 条信息中每条路径上的最小边权W从大到小排序,然后从每个U,V点出发直到到达它们的最近公共祖先

  在沿途中若遇到某条边有边权且大于W,则无法构建,否则把该边权设为W

  M条信息都操作完后输出答案即可

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define inf 1000000
#define rep(i , a , b) for(int i = a ; i <= b ; i ++)
const int N = 5e3 + 10;
int depth[N] , father[N] , val_pre[N] , index_pre[N] , ans[N];
vector<pair<int , int> >mat[N];
struct node{
    int x , y , w;
}q[N];
bool cmp(node a , node b)
{
    return a.w > b.w;
} 
void dfs(int now , int pre)
{
    depth[now] = depth[pre] + 1;
    father[now] = pre;
    for(auto i : mat[now])
    {
        if(i.first == pre) continue ;
        /// val_pre[i.first] 记录的是树中第 i.first →pre_i.first条边 , 
         /// 这条边在答案中的位置是 i.second 用index_pre来记录它在答案中的位置     
        dfs(i.first , now);
        index_pre[i.first] = i.second;
    }
    val_pre[now] = inf;
}
bool check(int x , int y , int w)
{
    int minn = inf;
    if(depth[x] < depth[y]) swap(x , y);
    while(depth[x] != depth[y])
    {
        if(val_pre[x] == inf)
        val_pre[x] = w;
        minn = min(minn , val_pre[x]);
        x = father[x];
    }
    while(x != y)
    {
        if(val_pre[x] == inf) val_pre[x] = w;
        minn = min(val_pre[x] , minn);
        x = father[x];
        if(val_pre[y] == inf) val_pre[y] = w;
        minn = min(val_pre[y] , minn); 
        y = father[y];
    }
    return minn == w;
}
signed main()
{
    ios::sync_with_stdio(false) , cin.tie(0);
    int n , m;
    cin >> n;
    rep(i , 1 , n)
    val_pre[i] = inf;
    rep(i , 1 , n - 1)
    {
        int u , v;
        cin >> u >> v;
        mat[u].push_back(make_pair(v , i)) , mat[v].push_back(make_pair(u , i));
    }          
    dfs(1 , 0); 
    cin >> m;
    rep(i , 1 , m)
    cin >> q[i].x >> q[i].y >> q[i].w;
    sort(q + 1 , q + 1 + m , cmp);
    rep(i , 1 , m)
        if(!check(q[i].x , q[i].y , q[i].w))
            return cout << -1 << '
' , 0;
    rep(i , 2 , n)
    ans[index_pre[i]] = val_pre[i];
    rep(i , 1 , n - 1)
    cout << ans[i] << " ";
    cout << '
';
    return 0;
}
凡所不能将我击倒的,都将使我更加强大
原文地址:https://www.cnblogs.com/StarRoadTang/p/12286085.html