Codeforces Round #617 (Div. 3) 题解

目录

  • Codeforces Round #617 (Div. 3) 题解

    • 前言
    • A. Array with Odd Sum
      • 题意
      • 做法
      • 程序
    • B. Food Buying
      • 题意
      • 做法
      • 程序
    • C. Yet Another Walking Robot
      • 题意
      • 做法
      • 程序
    • D. Fight with Monsters
      • 题意
      • 做法
      • 程序
    • E1. String Coloring (easy version)
      • 题意
      • 做法
      • 程序
    • E2. String Coloring (hard version)
      • 题意
      • 做法
      • 程序
    • F. Berland Beauty
      • 题意
      • 做法
      • 程序
    • 谢谢观看

Codeforces Round #617 (Div. 3) 题解

前言

这次比赛的题目都好有意思啊。STL真好用

包含题目:
CF 1296ACF 1296BCF 1296CCF 1296DCF 1296E1CF 1296E2CF 1296F

A. Array with Odd Sum

题意

给你一个序列,其中可以把任意一个的元素的值赋给任意一个另外的元素,这个操作可以进行任意次,也可不进行。问你能否把它们的和变成一个奇数。

做法

我们先计算奇数和偶数的个数,之后分类讨论:

  • 全是单数
    • 如果\(n\)是偶数,就输出NO
    • 如果\(n\)是奇数,就输出YES
  • 在有至少一个偶数的情况下
    • 如果没有奇数,输出NO
    • 如果有至少一个奇数,输出YES

程序

其中n&1可以简单的认为等价于n%2但是运算优先级不一样

#include<bits/stdc++.h>
using namespace std;

int t,n,a[2005];

int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin>>t;
    while(t--){
        cin>>n;
        int odd=0,even=0;
        for(int i=0;i<n;i++){
            cin>>a[i];
            if(a[i]&1){
                odd++;
            }else{
                even++;
            }
        }
        if(even==0){
            if(n&1){
                cout<<"YES"<<endl;
            }else{
                cout<<"NO"<<endl;
            }
        }else{
            if(odd==0){
                cout<<"NO"<<endl;
            }else{
                cout<<"YES"<<endl;
            }
        }
    }

    return 0;
}

B. Food Buying

题意

给你一个数\(s\)为初始钱数,你每次花\(x\)元,花完后可以返还\(\lfloor \frac x {10} \rfloor\)元(\(x\)除以\(10\)下取整)。问你最多能花出去多少钱。

做法

每次把个位数上的零头留着,花掉十位数往上的整钱,把返还的钱数和当前的钱数合并,再继续花下去。直到你只有零钱了,就全部花掉。

程序

#include<bits/stdc++.h>
using namespace std;

int t,n,ans;

int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin>>t;
    while(t--){
        cin>>n;
        ans=0;
        while(n>=10){
            ans+=n-n%10;
            n=n/10+n%10;
        }
        cout<<ans+n<<endl;
    }

    return 0;
}

C. Yet Another Walking Robot

题意

给你一个机器人,每一步可以上下左右走,再给一个机器人的移动步骤的字符串,让你删除一个非空子串(连续的),使得机器人停止的位置和没有删除之前停止的位置相同。

做法

前缀和,得到执行了每一步所停在的位置,如果有两个不同的字符串中的位置使得机器人停在的位置相同,那么可以删去第一个字符串中的位置往后一个到第二个字符串位置的子串。特别的,机器人未开始时在的位置也要计算进去。

程序

#include<bits/stdc++.h>
using namespace std;

int t,n;
string s;
int px;
int py;
map<pair<int,int>,set<int> > mp;

int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin>>t;
    while(t--){
        cin>>n;
        cin>>s;
        px=py=0;
        mp.clear();
        mp[make_pair(0,0)].insert(-1);
        for(int i=0;i<n;i++){
            px=px+(s[i]=='R')-(s[i]=='L');
            py=py+(s[i]=='U')-(s[i]=='D');
            mp[make_pair(px,py)].insert(i);
        }
        int ansl,ansr,ans=1e9;
        for(map<pair<int,int>,set<int> >::iterator it=mp.begin();it!=mp.end();it++){
            if(it->second.size()>1){
                vector<int> v;
                for(set<int>::iterator i=it->second.begin();i!=it->second.end();i++){
                    v.push_back(*i);
                }
                for(int l=0,r=0;l<v.size();l++){
                    while(r<v.size()&&v[r]-v[l]<=0)r++;
                    if(r==v.size())break;
                    if(v[r]-v[l]<ans){
                        ans=v[r]-v[l];
                        ansl=v[l]+2;
                        ansr=v[r]+1;
                    }
                }
            }
        }
        if(ans==1e9){
            cout<<-1<<endl;
        }else{
            cout<<ansl<<' '<<ansr<<endl;
        }
    }

    return 0;
}

D. Fight with Monsters

题意

\(n\)个怪物,每个血量\(h_i\),你攻击力\(a\),你对手攻击力\(b\),怪物血量小于等于\(0\)时死亡。遇到怪物时你先手,你对手后手,轮流攻击,造成最后一击的人拿到分数。你可以跳过你对手的回合\(k\)次,使他不能攻击。你们从第一个怪物打到第\(n\)个,问你能拿到的最大的分数。

做法

对于每个怪物,我们计算你造成最后一击所需要的跳过对手回合的次数:

  • 首先把怪物的血量对\(a+b\)取模,之后如果是\(0\),那么再加上\(a+b\),保证不跳过的话,你和对手攻击过后怪物必定死亡。
  • 然后计算你要打\(c_i\)次杀死怪物,那么显然需要跳过你的对手\(c_i-1\)次。

把\(c_i-1\)的数组排个序从小到大贪心的使用\(k\)次机会即可。

程序

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

ll n,a,b,k;
ll h[200005];

int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin>>n>>a>>b>>k;
    for(ll i=0;i<n;i++){
        cin>>h[i];
        h[i]%=a+b;
        if(h[i]==0)h[i]+=a+b;
        h[i]=(h[i]-1)/a;
    }
    sort(h,h+n);
    ll ans=0;
    for(int i=0;i<n;i++){
        k-=h[i];
        if(k>=0)ans++;
        else break;
    }
    cout<<ans<<endl;

    return 0;
}

E1. String Coloring (easy version)

题意

给你一个字符串,让你把它涂成两种颜色,可以交换相邻的不同颜色的元素,问你能不能把它搞成有序的。

做法

显然交换相邻是冒泡排序的思想。可以看出,消除逆序对,需要它们的颜色不同,于是,我们可以分别维护颜色为\(0\)和\(1\)的目前元素的最大值,从前到后的处理字符串,贪心的先涂成\(0\),假如\(0\)中元素的最大值比它大,那么就会造成不能排序,此时就涂成\(1\),假如还是有最大值比它大,那么就输出-1,否则就更新当前颜色的最大值,就可以了。

程序

#include<bits/stdc++.h>
using namespace std;

int n;
string s;
int col[205];
int cnt,mx[2];

int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin>>n;
    cin>>s;
    for(int i=0;i<n;i++){
        if(mx[0]>s[i]){
            if(mx[1]>s[i]){
                cout<<"NO"<<endl;
                return 0;
            }else{
                mx[1]=s[i];
                col[i]=1;
            }
        }else{
            mx[0]=s[i];
            col[i]=0;
        }
    }
    cout<<"YES"<<endl;
    for(int i=0;i<n;i++)cout<<col[i];
    cout<<endl;

    return 0;
}

E2. String Coloring (hard version)

题意

请照着E1理解。现在你可以涂无限多种颜色,求搞成有序序列最少要涂多少种不同的颜色。

做法

基本想法还是相同的。消除逆序对需要两个端点是不同的颜色,于是我们就记录每一种颜色对应的最大值,保存为数组。我们把保存颜色\(i\)中最大的元素的数组叫作\(mx_i\),对于每一位\(s_i\)的更新,我们需要快速的查询这个数组中第一个比\(s_i\)小或者相同的元素位置。由于每一次更新第\(i\)位时,保证\(mx\)前面的元素都比\(i\)大,所以这个数组单调递减,可以二分地找到这个位置。

程序

#include<bits/stdc++.h>
using namespace std;

int n,sz,ans;
char s[200005];
int col[200005];
int mx[200005];

int qry(int val){
    int l=1,r=n,m,res;
    while(l<=r){
        m=(l+r)>>1;
        if(mx[m]<=val){
            res=m;
            r=m-1;
        }else{
            l=m+1;
        }
    }
    return res;
}

int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin>>n;
    sz=1;while(sz<n)sz<<=1;
    cin>>s+1;
    for(int i=1;i<=n;i++){
        int pos=qry(s[i]);
        mx[pos]=s[i];
        col[i]=pos;
        ans=max(ans,pos);
    }
    cout<<ans<<endl;
    for(int i=1;i<=n;i++)cout<<col[i]<<' ';
    cout<<endl;

    return 0;
}

F. Berland Beauty

题意

给你一棵树,每条边有一个权值,告诉你数个条件,每个条件告诉你某两点之间的简单路径上的所有的边中权值最小的一条边的权值,问你能否构建出这样的满足所有条件的树,并输出可行方案。

做法

由于数据范围十分的小,所以暴力就好了。

我们首先规定\(1\)是这棵树的根,然后预处理每个节点的深度。然后,两个节点\(u,v\)间的简单路径,必定是\(u\)到\(lca(u,v)\)和\(v\)到\(lca(u,v)\)的这段路程的和,此处\(lca(u,v)\)是\(u,v\)的最近公共祖先(有根树意义下)。于是简单路径便可以这么求得:把较深的节点通过不断的变换为它的父亲的方式提上来,之后同时提两个节点,直到变成同一个。经过的边就是它们之间的简单路径。

对于每一条边,为了满足条件,它的权值必定是所有影响它的条件中的权值的最大值,我们直接把它的权值就固定了,假如没有影响它的边,我们就赋值为任意的值。比如114514

最后我们在查看一遍每个条件是否满足了就好了。

程序

#include<bits/stdc++.h>
using namespace std;

int n,m;
vector<pair<int,int> > g[5005];
pair<pair<int,int>,int> q[5005];
int d[5005];
pair<int,int> par[5005];
int f[5005];

void dfs(int x,int p,int cd){
    d[x]=cd;
    for(int i=0;i<g[x].size();i++){
        int &y=g[x][i].first,&z=g[x][i].second;
        if(y!=p){
            dfs(y,x,cd+1);
            par[y]=make_pair(x,z);
        }
    }
}

int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin>>n;
    for(int i=1;i<n;i++){
        int a,b;
        cin>>a>>b;
        g[a].push_back(make_pair(b,i));
        g[b].push_back(make_pair(a,i));
        f[i]=1;
    }
    dfs(1,-1,1);
    cin>>m;
    for(int i=1;i<=m;i++){
        int a,b,c;
        cin>>a>>b>>c;
        q[i]=make_pair(make_pair(a,b),c);
        if(d[a]>d[b])swap(a,b);
        while(d[b]>d[a]){
            f[par[b].second]=max(f[par[b].second],c);
            b=par[b].first;
        }
        while(b!=a){
            f[par[a].second]=max(f[par[a].second],c);
            a=par[a].first;
            f[par[b].second]=max(f[par[b].second],c);
            b=par[b].first;
        }
    }
    for(int i=1;i<=m;i++){
        bool fl=false;
        int a,b,c;
        a=q[i].first.first;
        b=q[i].first.second;
        c=q[i].second;
        if(d[a]>d[b])swap(a,b);
        while(d[b]>d[a]){
            if(f[par[b].second]==c)fl=true;
            b=par[b].first;
        }
        while(b!=a){
            if(f[par[a].second]==c)fl=true;
            a=par[a].first;
            if(f[par[b].second]==c)fl=true;
            b=par[b].first;
        }
        if(!fl){
            cout<<-1<<endl;
            return 0;
        }
    }
    for(int i=1;i<n;i++){
        cout<<f[i]<<' ';
    }
    cout<<endl;

    return 0;
}

谢谢观看

emmm,觉得E题的贪心写得很烂,主要赛时突然就想到了,感性理解一波就直接交了,有什么不懂的可以问啦。

会有人看&问吗

原文地址:https://www.cnblogs.com/BlahDuckling747/p/12264691.html

时间: 2024-08-09 05:11:39

Codeforces Round #617 (Div. 3) 题解的相关文章

[Codeforces Round #617 (Div. 3)] 题解 A,B,C,D,E1,E2,F

[Codeforces Round #617 (Div. 3)] 题解 A,B,C,D,E1,E2,F 1296A - Array with Odd Sum 思路: 如果一开始数组的sum和是奇数,那么直接YES, 否则:如果存在一个奇数和一个偶数,答案为YES,否则为NO 代码: int n; int a[maxn]; int main() { //freopen("D:\\code\\text\\input.txt","r",stdin); //freopen(

Codeforces Round #617 (Div. 3) 题解 1296C 1296D 1296E 1296F

C 对每一步结束之后往map里存个位置,看停留在相同位置的最少差多少步就行了. D 由\(h\%(a+b)\leq (x+1)a\)得\(x_{min}=\lceil\frac{h\%(a+b)}{a}\rceil-1\).然后贪心即可. E1 注意到要把原字符串排序,每一对逆序对都要进行一次交换,即每一对逆序对的颜色都必须不同.因此所需的颜色数即为最长的逆序链长. 对E1,可以考虑建图,每个位置看成一个点,把每一对逆序对建边,很显然这就是判断是不是一张二分图. E2 对E2,依次考虑字母a,b

Codeforces Round #262 (Div. 2) 题解

A. Vasya and Socks time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Vasya has n pairs of socks. In the morning of each day Vasya has to put on a pair of socks before he goes to school. When

Codeforces Round #FF (Div. 2) 题解

比赛链接:http://codeforces.com/contest/447 A. DZY Loves Hash time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output DZY has a hash table with p buckets, numbered from 0 to p?-?1. He wants to insert n 

Codeforces Round #259 (Div. 2) 题解

A. Little Pony and Crystal Mine time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Twilight Sparkle once got a crystal from the Crystal Mine. A crystal of size n (n is odd; n?>?1) is an n?×?n 

Codeforces Round #177 (Div. 2) 题解

[前言]咦?现在怎么流行打CF了?于是当一帮大爷在执着的打div 1的时候,我偷偷的在刷div 2.至于怎么决定场次嘛,一般我报一个数字A,随便再拉一个人选一个数字B.然后开始做第A^B场.如果觉得机密性不高,来点取模吧.然后今天做的这场少有的AK了.(其实模拟赛只做完了4题,最后1题来不及打了) 等等,话说前面几题不用写题解了?算了,让我难得风光一下啦. [A] A. Polo the Penguin and Segments time limit per test 2 seconds mem

Codeforces Round #534 (Div. 2)题解

Codeforces Round #534 (Div. 2)题解 A. Splitting into digits 题目大意 将一个数字分成几部分,几部分求和既是原数,问如何分可以使得分出来的各个数之间的差值尽可能小 解题思路 将n分成n个1相加即可 AC代码 #include<cstring> #include<string> #include<iostream> #include<cstdio> using namespace std; int main

Codeforces Round #561 (Div. 2) 题解

Codeforces Round #561 (Div. 2) 题解 题目链接 A. Silent Classroom 水题. Code #include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 105; int n; char s[N], t[N]; int main() { cin >> n; for(int i = 1; i <= n; i++) { scanf(&q

Codeforces Round #608 (Div. 2) 题解

目录 Codeforces Round #608 (Div. 2) 题解 前言 A. Suits 题意 做法 程序 B. Blocks 题意 做法 程序 C. Shawarma Tent 题意 做法 程序 D. Portals 题意 做法 程序 E. Common Number 题意 做法 程序 结束语 Codeforces Round #608 (Div. 2) 题解 前言 题目链接:仅仅只是为了方便以题目作为关键字能查找到我的题解而已(逃 Codeforces 1271A Codeforce