Codeforces Round #805 (Div. 3)(A-G1)

目录

A. Round Down the Price

B. Polycarp Writes a String from Memory 

C. Train and Queries

D. Not a Cheap String

E. Split Into Two Sets

F. Equate Multisets

G1. Passable Paths (easy version)


A. Round Down the Price

题意:给一个数,该数减去需要求的一个数后,会是最大的10的某次方数。

输入:

7
1
2
178
20
999999999
9000
987654321

输出:

0
1
78
10
899999999
8000
887654321

思路:

找出和该数同位的10的幂数,减去即可

代码:

#include
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define M 1000005
int T,n,s;
signed main(){
    cin>>n;
    fo(1,n){
        cin>>s;
        int ans=1;
        int ss=s;
        while(ss) ans*=10,ss/=10;
        cout<

B. Polycarp Writes a String from Memory 

题意:一个字符串只能从前往后取,每次最多取三种不一样的字符,求最少多少次取完

输入:

6
lollipops
stringology
abracadabra
codeforces
test
f

输出:

2
4
3
4
1
1

思路:

暴力模拟,用数组存是否已经取过,超过4个的点就是下次取的第一个点,最后的没取到3种的也算1次

代码:

#include
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define mem(a,b) memset(a,b,sizeof(a))
#define M 1000005
int T,n;
int vis[205];
string s;
signed main(){
    cin>>T;
    while(T--){
        cin>>s;
        mem(vis,0);     //清空
        int l=(int)s.size();
        int sum=0,s1=0;
        fo(0,l-1){
            if(vis[s[i]]==0) sum++;
            if(sum==4){     //超了的话,该点就算下次取的第一点
                s1++;
                mem(vis,0);      //清空
                sum=1;
            }
            vis[s[i]]=1;
        }
        cout<

C. Train and Queries

题意:给一个数组,前面的点能到后面的任意一点,但是后面的不能到前面,且不能到路的中间(即只有起点到终点)。问两点能不能到

输入:

3

6 3
3 7 1 5 1 4
3 5
1 7
3 10

3 3
1 2 1
2 1
1 2
4 5

7 5
2 1 1 1 2 4 4
1 3
1 4
2 1
4 1
1 2

输出:

YES
NO
NO
YES
YES
NO
NO
YES
YES
NO
YES

思路:

一个点为起点的话,最记最前面的点的位置即可,因为后面的该点能到,前面的也一定能到。

终点只记末尾位置即可,要是起点位置比终点大,或者没有该点出现直接输出NO

代码:

#include
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define M 1000005
int T,n,m,l,r;
int a[M];
mapmpx,mpy;
signed main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        mpx.clear();
        mpy.clear();
        fo(1,n) cin>>a[i],mpx[a[i]]=i;      //mpx为点的终点位置
        for(int i=n;i>=1;i--) mpy[a[i]]=i;      //起点
        while(m--){
            cin>>l>>r;
            if(mpy[l]==0||mpx[r]==0||mpy[l]>mpx[r]) cout<<"NO"<

D. Not a Cheap String

题意:一些字符串,s[i]的价值是s[i]-'a'+1,找出长度最长的子序列价值和<=k。

输入:

5
abca
2
abca
6
codeforces
1
codeforces
10
codeforces
100

输出:

aa
abc

cdc
codeforces

思路:

贪心选即可,从'a'开始选,选完后根据标记找出这个子序列

代码:

#include
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define mem(a,b) memset(a,b,sizeof(a))
#define M 1000005
int T,n,k;
int vis[205],v[205];
char s[M];
signed main(){
    scanf("%d",&T);
    while(T--){
        mem(vis,0);
        mem(v,0);
        scanf("%s",s);
        n=strlen(s);
        scanf("%d",&k);
        fo(0,n-1) vis[s[i]]++;
        int j='a';
        while(k>=1&&j<='z'){
            if(vis[j]&&k-(j-'a'+1)>=0) vis[j]--,v[j]++,k-=(j-'a'+1);        //v[j]表示字符j已选的数量
            else j++;
        }
        string tmp;
        fo(0,n-1){
            if(v[s[i]]){        //根据已选数量选择字符
                v[s[i]]--;
                tmp+=s[i];
            }
        }
        cout<

E. Split Into Two Sets

题意:给n个二元组,问能不能分成两份,每份中没有重复的数字。

输入:

6
4
1 2
4 3
2 1
3 4
6
1 2
4 5
1 3
4 6
2 3
5 6
2
1 1
2 2
2
1 2
2 1
8
2 1
1 2
4 3
4 3
5 6
5 7
8 6
7 8
8
1 2
2 1
4 3
5 3
5 4
6 7
8 6
7 8

输出:

YES
NO
NO
YES
YES
NO

思路:

首先里面的数字是1-n的,那么每份的数字一定会是1-n,也就是每份二元组的数量一定是n/2的。

所以每个数字出现次数就是2次,每个点能到达的也就是两个点(类似于双边的图)。

从一个点开始走,路是唯一的,直到遇到已经走过的点,而该点一定是出发点,这样就形成一个闭环,这个闭环点的数量为奇数的话,答案就是NO。

比如

3

1 1

2 3

2 3

从1出发在1处闭环,数量为奇数答案直接为NO;从2出发到3,再到2为闭环,数量为2不影响答案。

代码:

#include
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define M 1000005
int T,n,x,y;
int vis[M];
vectorv[M];
signed main(){
    scanf("%d",&T);
    for(int k=1;k<=T;k++){
        int flag=0;
        scanf("%d",&n);
        fo(1,n) v[i].clear();
        fo(1,n){
            scanf("%d%d",&x,&y);
            v[x].push_back(y);
            v[y].push_back(x);
        }
        fo(1,n){
            if(v[i].size()!=2){
                flag=1;
                break;
            }
            int id=i,sum=0;
            while(vis[id]!=k){      //id表示从i点出发的路径点
                vis[id]=k;      //标记id点走过
                sum++;
                if(vis[v[id][0]]!=k) id=v[id][0];       //如果一个点没有过就走
                else id=v[id][1];
            }
            if(sum%2) flag=1;
        }
        printf("%s\n",flag?"NO":"YES");
    }
    return 0;
}


F. Equate Multisets

题意:给两个数组,问b数组中的数组随便除以2向下取整,或者随便乘以2,能不能为a数组

输入:

5
4
2 4 5 24
1 4 6 11
3
1 4 17
4 5 31
5
4 7 10 13 14
2 14 14 26 42
5
2 2 4 4 4
28 46 62 71 98
6
1 2 10 16 64 80
20 43 60 74 85 99

输出:

YES
NO
YES
YES
YES

思路:

a数组中所有偶数不停/2变为奇数,不会影响答案,比如a中的10,b中有一个数能变为10,就一定可以变为5

b数组同理,都不停/2变为奇数

那么此时的b数组只能做/2一种了,因为a数组都是奇数,你乘2是不是也没有用

map存一下a数组中的奇数,b数组不停的/2,匹配即可

代码:

#include
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define int long long
#define M 1000005
int T,n,f=0;
int a[M],b[M];
mapmp;
void solve(int &x){         //除2
    while(x%2==0) x/=2;
}
string fin(){
    fo(1,n){
        while(b[i]&&mp[b[i]]==0) b[i]/=2;
        if(!b[i]) return "NO";
        mp[b[i]]--;
    }
    return "YES";
}
signed main(){
    scanf("%lld",&T);
    while(T--){
        mp.clear();
        scanf("%lld",&n);
        fo(1,n) cin>>a[i],solve(a[i]),mp[a[i]]++;
        fo(1,n) cin>>b[i],solve(b[i]);
        cout<

G1. Passable Paths (easy version)

题意:给一个树,问如若干个点是否在树上是一个链,也就是有没有一条不回头的路穿过所有给定的点

输入:

5
1 2
2 3
2 4
4 5
5
3
3 2 5
5
1 2 3 4 5
2
1 4
3
1 3 5
3
1 5 4

输出:

YES
NO
YES
NO
YES

思路:这个是easy版本的,询问只有5次以下,我的思路是预处理高度,高度最大的点一定是该链的起点,每次需要从该点dfs遍历整个树,将出现过的点+1,问有没有加到点的数量的。

但是这个方法对hard的下题就不行了

代码:

#include
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define int long long
#define M 200005
int T,n,m,x,y,l,flag;
int q[M];
vectorv[M];
int h[M];
mapmp;
int cmp(int x,int y){
    return h[x]>h[y];
}
void dfs(int d,int pre)
{
    h[d]=h[pre]+1;          //处理高度
    int l=v[d].size();
    fo(0,l-1){
        int now=v[d][i];
        if(pre!=now){
            dfs(now,d);
        }
    }
}
void qdfs(int d,int pre,int s)
{
    if(s==l){       //如果等于询问点的数量,答案是YES
        flag=1;
        return;
    }
    int l=v[d].size();
    fo(0,l-1){
        int now=v[d][i];
        if(pre!=now){
            int res=mp[now];
            qdfs(now,d,s+res);          //s+是否是询问的点
        }
    }
}
signed main(){
    cin.tie(nullptr)->sync_with_stdio(false);
    cin>>n;
    fo(1,n-1){
        cin>>x>>y;
        v[x].push_back(y);
        v[y].push_back(x);
    }
    dfs(1,0);
    cin>>m;
    while(m--){
        flag=0;
        mp.clear();
        cin>>l;
        fo(1,l) cin>>q[i],mp[q[i]]=1;
        sort(q+1,q+l+1,cmp);
        qdfs(q[1],0,1);             //从高度最大的点开始遍历
        cout<<(flag?"YES":"NO")<

你可能感兴趣的:(比赛题解,大数据)