Codeforces Round #312 (Div. 2) A~E && CDE题解

PS:因为是很久之前做的然后现在补,所以前几道的题意我也不知道QAQ

A. Lala Land and Apple Trees

Problem Description
Amr lives in Lala Land. Lala Land is a very beautiful country that is located on a coordinate line. Lala Land is famous with its apple trees growing everywhere.

Lala Land has exactly n apple trees. Tree number i is located in a position xi and has ai apples growing on it. Amr wants to collect apples from the apple trees. Amr currently stands in x = 0 position. At the beginning, he can choose whether to go right or left. He’ll continue in his direction until he meets an apple tree he didn’t visit before. He’ll take all of its apples and then reverse his direction, continue walking in this direction until he meets another apple tree he didn’t visit before and so on. In the other words, Amr reverses his direction when visiting each new apple tree. Amr will stop collecting apples when there are no more trees he didn’t visit in the direction he is facing.

What is the maximum number of apples he can collect?

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<queue>
#include<stack>
#include<string>
#include<vector>
#include<map>
#include<set>
using namespace std;
#define rfor(i,a,b) for(i=a;i<=b;++i)
#define lfor(i,a,b) for(i=a;i>=b;--i)
#define sfor(i,a,h) for(i=h[a];i!=-1;i=e[i].next)
#define mem(a,b) memset(a,b,sizeof(a))
#define mec(a,b) memcpy(a,b,sizeof(b))
#define cheak(i) printf("%d ",i)
#define min(a,b) (a>b?b:a)
#define max(a,b) (a>b?a:b)
#define inf 0x7fffffff
#define lowbit(x) (x&(-x))
typedef long long LL;
struct node
{
    int pos,val;
}s[105];
int cmp(node u,node v)
{
    return u.pos<v.pos;
}
int main()
{
    int i,n;
    scanf("%d",&n);
    rfor(i,1,n)
    scanf("%d%d",&s[i].pos,&s[i].val);
    sort(s+1,s+n+1,cmp);
    rfor(i,1,n)
    if(s[i].pos>0) break;
    int l=i-1;
    int r=n-l,sum;
    if(l>r)
    {
        sum=0;
        lfor(i,n,n-2*r)
        {
            sum+=s[i].val;
        }
    }
    else if(l<r)
    {
        sum=0;
        rfor(i,1,l*2+1)
        {
            sum+=s[i].val;
        }
    }
    else
    {
        sum=0;
        rfor(i,1,n)
        sum+=s[i].val;
    }
    printf("%d\n",sum);
    return 0;
}

B. Amr and The Large Array

Problem Description
Amr has got a large array of size n. Amr doesn’t like large arrays so he intends to make it smaller.

Amr doesn’t care about anything in the array except the beauty of it. The beauty of the array is defined to be the maximum number of times that some number occurs in this array. He wants to choose the smallest subsegment of this array such that the beauty of it will be the same as the original array.

Help Amr by choosing the smallest subsegment possible.

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<queue>
#include<stack>
#include<string>
#include<vector>
#include<map>
#include<set>
using namespace std;
#define rfor(i,a,b) for(i=a;i<=b;++i)
#define lfor(i,a,b) for(i=a;i>=b;--i)
#define sfor(i,a,h) for(i=h[a];i!=-1;i=e[i].next)
#define mem(a,b) memset(a,b,sizeof(a))
#define mec(a,b) memcpy(a,b,sizeof(b))
#define cheak(i) printf("%d ",i)
#define min(a,b) (a>b?b:a)
#define max(a,b) (a>b?a:b)
#define inf 0x7fffffff
#define lowbit(x) (x&(-x))
typedef long long LL;
#define maxn 100005
int A[maxn],mark[maxn*10],pos[maxn*10];
int main()
{
    int n,i,m=0;
    scanf("%d",&n);
    rfor(i,1,n)
    {
        scanf("%d",&A[i]);
        mark[A[i]]++;
        m=max(mark[A[i]],m);
    }
    mem(mark,0);
    int ans=inf,flag;
    rfor(i,1,n)
    {
        if(!mark[A[i]])
        {
            mark[A[i]]++;
            pos[A[i]]=i;
        }
        else
        {
            mark[A[i]]++;
        }
        if(mark[A[i]]==m)
        {
            if(i-pos[A[i]]<ans)
            {
                ans=i-pos[A[i]];
                flag=i;
            }
        }
    }
    printf("%d %d\n",flag-ans,flag);
    return 0;
}

C. Amr and Chemistry

Problem Description
Amr loves Chemistry, and specially doing experiments. He is preparing for a new interesting experiment.

Amr has n different types of chemicals. Each chemical i has an initial volume of ai liters. For this experiment, Amr has to mix all the chemicals together, but all the chemicals volumes must be equal first. So his task is to make all the chemicals volumes equal.

To do this, Amr can do two different kind of operations.

Choose some chemical i and double its current volume so the new volume will be 2ai
Choose some chemical i and divide its volume by two (integer division) so the new volume will be
Suppose that each chemical is contained in a vessel of infinite volume. Now Amr wonders what is the minimum number of operations required to make all the chemicals volumes equal?
题意:
给你n个数,让你通过*2或者/2来使所有数相同最少的步数
思路:
这里先发现数据范围是1~1e5的(如果突破点不在这的话,那么一定是1~1e9…
所以我们可以枚举每个数可以达到的每个状态和步数
然后再枚举所有有n个数能达到的状态中最小的步数
这里有一点比较特殊就是比如3,3可以达到4
3/2=1,1*2*2=4
特殊处理一下这种就行了

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<queue>
#include<stack>
#include<string>
#include<vector>
#include<map>
#include<set>
using namespace std;
#define lowbit(x) (x&(-x))
typedef long long LL;
const int maxn = 200005;
const int inf=(1<<28)-1;
int A[maxn],Top[maxn],Down[maxn],Cnt[maxn];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%d",&A[i]);
    memset(Top,0,sizeof(Top));
    memset(Down,0,sizeof(Down));
    memset(Cnt,0,sizeof(Cnt));
    for(int i=1;i<=n;++i)
    {
        LL tmp=1,now=0;
        while(A[i]*tmp<maxn)
        {
            Top[A[i]*tmp]++;
            Cnt[A[i]*tmp]+=now;
            tmp<<=1;
            now++;
        }
        now=0;
        while(A[i]>1)
        {
            if(A[i]&1 && 1!=A[i])
            {
                int tmp=A[i]>>1,tmp_now=now+1;
                while(tmp<maxn)
                {
                    Down[tmp]++;
                    Cnt[tmp]+=tmp_now;
                    tmp_now++;
                    tmp<<=1;
                }
                now++;
                A[i]>>=1;
            }
            else
            {
                now++;
                A[i]>>=1;
                Down[A[i]]++;
                Cnt[A[i]]+=now;
            }
        }
    }
    int ans=inf;
    //for(int i=1;i<=20;++i) printf("%d: %d %d %d\n",i,Top[i],Down[i],Cnt[i]);
    for(int i=1;i<maxn;++i)
    if(Top[i]+Down[i]==n)
    ans=min(ans,Cnt[i]);
    printf("%d\n",ans);
    return 0;
}

D. Guess Your Way Out! II

Problem Description
Amr bought a new video game “Guess Your Way Out! II”. The goal of the game is to find an exit from the maze that looks like a perfect binary tree of height h. The player is initially standing at the root of the tree and the exit from the tree is located at some leaf node.

Let’s index all the nodes of the tree such that

The root is number 1
Each internal node i (i ≤ 2h - 1 - 1) will have a left child with index = 2i and a right child with index = 2i + 1
The level of a node is defined as 1 for a root, or 1 + level of parent of the node otherwise. The vertices of the level h are called leaves. The exit to the maze is located at some leaf node n, the player doesn’t know where the exit is so he has to guess his way out!

In the new version of the game the player is allowed to ask questions on the format “Does the ancestor(exit, i) node number belong to the range [L, R]?”. Here ancestor(v, i) is the ancestor of a node v that located in the level i. The game will answer with “Yes” or “No” only. The game is designed such that it doesn’t always answer correctly, and sometimes it cheats to confuse the player!.

Amr asked a lot of questions and got confused by all these answers, so he asked you to help him. Given the questions and its answers, can you identify whether the game is telling contradictory information or not? If the information is not contradictory and the exit node can be determined uniquely, output its number. If the information is not contradictory, but the exit node isn’t defined uniquely, output that the number of questions is not sufficient. Otherwise output that the information is contradictory.
题意:
给以一颗高为h的满二叉树
然后Q组提示,问你提示之间是否冲突,通过提示是否能找到一个确定的点
每个提示是高度为i的节点中L~R的所有儿子节点和本身ans=0不是(ans=1可能是)答案
要找的点一定是叶子节点
思路:
我们把L~R转化成当前高度的left~L-1和R+1~right可能是答案就行了
然后找是否有一组解被所有区间覆盖就行了

E. A Simple Task

Problem Description
This task is very simple. Given a string S of length n and q queries each query is on the format i j k which means sort the substring consisting of the characters from i to j in non-decreasing order if k = 1 or in non-increasing order if k = 0.

Output the final string after applying the queries.
题意:
给一个长度为n的串,有q组操作,问操作后的串
每组操作有L,R,kind代表从L~R排序
如果kind==1就从小到大,否则从大到小
思路:
先思考暴力,复杂度O(qnlogn)
发现我们这个串是字符串,所以排序可以用基数排序时间复杂度O(q*n)
我们可以把从L~R排序考虑成拿出L~R的所有字符,统计个数,基数排序
然后再放回去.如果是正序,就从小到大放进去
这样就可以考虑使用26颗线段树,每颗保存单个字母的信息
时间复杂度O(26qlogn) AC

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
const int maxn = 500005;
char str[maxn];
int Sum[maxn<<2][26],lazy[maxn<<2][26];
void Push_down(int k,int rt,int Id)
{
    if(lazy[rt][Id]==-1) return ;
    lazy[rt*2][Id]=lazy[rt*2+1][Id]=lazy[rt][Id];
    if(lazy[rt][Id]) 
    {
        Sum[rt*2][Id]=(k+1)/2;
        Sum[rt*2+1][Id]=k/2;
    }
    else Sum[rt*2][Id]=Sum[rt*2+1][Id]=0;
    lazy[rt][Id]=-1;
}
void Insert(int left,int right,int l,int r,int rt,int kind,int Id)
{
    if(left<=l&&r<=right)
    {
        if(kind) Sum[rt][Id]=r-l+1;
        else Sum[rt][Id]=0;
        lazy[rt][Id]=kind;
        return ;
    }
    Push_down(r-l+1,rt,Id);
    int mid=(l+r)/2;
    if(left<=mid) Insert(left,right,l,mid,rt*2,kind,Id);
    if(right>mid) Insert(left,right,mid+1,r,rt*2+1,kind,Id);
    Sum[rt][Id]=Sum[rt*2][Id]+Sum[rt*2+1][Id];
}
int Query(int left,int right,int l,int r,int rt,int Id)
{
    if(left<=l&&r<=right) return Sum[rt][Id];
    Push_down(r-l+1,rt,Id);
    int mid=(l+r)/2;
    int res=0;
    if(left<=mid) res+=Query(left,right,l,mid,rt*2,Id);
    if(right>mid) res+=Query(left,right,mid+1,r,rt*2+1,Id);
    return res;
}
void Print(int l,int r,int rt)
{
    for(int i=0;i<26;++i)
    Push_down(r-l+1,rt,i);
    if(l==r)
    {
        for(int i=0;i<26;++i)
        if(Sum[rt][i])
        {
            printf("%c",i+'a');
            return ;
        }
        //return ;
    }
    int mid=(l+r)/2;
    Print(l,mid,rt*2);
    Print(mid+1,r,rt*2+1);
}
int Cnt[26];
int main()
{
    memset(lazy,-1,sizeof(lazy));
    memset(Sum,0,sizeof(Sum));
    int n,q;
    scanf("%d%d",&n,&q);
    scanf("%s",str+1);
    int len=strlen(str+1);
    for(int i=1;i<=len;++i)
    Insert(i,i,1,n,1,1,str[i]-'a');
    while(q--)
    {
        int L,R,kind;
        scanf("%d%d%d",&L,&R,&kind);
        for(int i=0;i<26;++i)
        {
            Cnt[i]=Query(L,R,1,n,1,i);
            Insert(L,R,1,n,1,0,i);
        }
        //for(int i=0;i<26;++i) if(Cnt[i]) printf("%c:%d ",i+'a',Cnt[i]);printf("\n");
        if(kind)
        {
            int tmp_pos=L;
            for(int i=0;i<26;++i)
            if(Cnt[i])
            {
                Insert(tmp_pos,tmp_pos+Cnt[i]-1,1,n,1,1,i);
                tmp_pos+=Cnt[i];
            }
        }
        else
        {
            int tmp_pos=L;
            for(int i=25;i>=0;--i)
            if(Cnt[i])
            {
                Insert(tmp_pos,tmp_pos+Cnt[i]-1,1,n,1,1,i);
                tmp_pos+=Cnt[i];
            }
        }
        //Print(1,n,1);
    }
    Print(1,n,1);
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值