Codeforces Round #378 (Div. 2)A.B.C

86 篇文章 0 订阅

又是一次智障的跌在C题,大哭不多记了,看代码。。。

A题:

题意:

虫子每次都可以跳到他所在位置前面的第一个A,E,I,O,U,Y的出现位置,并且最后可以跳到最后。

思路:

暴力扫一遍位置就行了,注意下尾部字符串末尾终止处理,比赛时候智障了。

#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;
char s[100005];
int a[10005];
int main()
{
    scanf("%s",&s);
    int ans=0;
    int tep=0;
    int len=0;
    a[1]=0;
    for(int i=0;i<strlen(s);i++)
    {
        if(s[i]=='A'||s[i]=='E'||s[i]=='O'||s[i]=='I'||s[i]=='U'||s[i]=='Y')
        {
            a[++len]=i+1;

        }
    }
    a[++len]=1+strlen(s);
    for(int i=1;i<=len;i++)
    {
        //cout<<a[i]<<" ";
        ans=max(a[i]-a[i-1],ans);
    }
    cout<<ans<<endl;
    return 0;
}


B题:

题意:士兵走步,第一个数据N,下面有N对, 

第一个数据表示第一次迈左腿的人数, 第二个数据表示第一次迈右腿的人数。

询问,你只能交换一次,也可以不交换,使得所有的第一次迈左腿的,与右腿的人数差值的绝对值最大

思路:

先记录左腿,右腿依次的和,然后暴力交换每一行。

#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;
char s[100005];
int a[10005];
int l[1000005];
int r[1000005];
int lx[1000005];
int rx[1000005];
int main()
{
    int k;
    cin>>k;
    int suml=0,sumr=0;
    for(int i=1;i<=k;i++)
    {
        cin>>l[i]>>r[i];
        suml+=l[i];
        sumr+=r[i];
    }
    int maxx=sumr-suml;
    if(maxx<0)
        maxx=-maxx;
    int ans=0;
    for(int i=1;i<=k;i++)
    {
        int tel=suml-l[i]+r[i];
        int ter=sumr-r[i]+l[i];
        int maxt=tel-ter;
        if(maxt<0)
            maxt=-maxt;
        if(maxt>maxx)
        {
            maxx=maxt;
            ans=i;
        }

    }
    cout<<ans<<endl;

    return 0;
}

C题:

这题编了一个半小时不出,最后24秒发现扫一下就可以了,第二天15分钟就AC了。真是个智障哭

题意:

第一行N,表示第二行有n个数字

第二行有N个数字

第三行K,表示第四行有K个数字

第四行 K个数字。

题目背景是:  第二行都是怪物,数字大的吃数字小的,并且只能吃掉相邻的,吃掉后变为两个数字的和,询问能否通过怪物互相吃掉对方,变成第四行的数字。

  思路:

注意点四行的K个数字,如果我们拿到第一个数字的话,那一定这个数字是通过第二行前X个构造的,第二个数字,必定是通过第二行前X+1->Y个数字构造的,那么我们只需要如此做就AC嘞!(注意,因为怪物不能直接互换位置,所以只需要扫一下和就行了)

1: 扫一下第二行,记录数字的和,如果数字的和==第四行的第i个数字,就把当前记录清空,继续找i+1个,否则找不到就跳出去。(具体见程序solve函数有注释)

2: 如果可以将这些数字经过若干步,变成第四行要求的数字,那么我们只需要再重新调用下之前的函数,把操作打印出来即可。

3: (掉坑里的一步): 什么也别想,直接暴力扫一下,数据很小,我们只需要记录下当前的最大值的位置,然后进行左或者右的判断,以及开始位置。

如果没看懂,看代码:

#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;
int a[10005];
int need[10005];
int pos[10005];
int vis[10005];
int all;
int solve(int x,int op )
{
    memset(vis,0,sizeof(vis));
    int maxx=0;
    int cnt=0;
    //记录最大值所在的位置。如果都是最大值那就不成立,第一次调用solve函数时候的判断
    for(int i=pos[x-1]+1;i<=pos[x];i++)
    {
        if(a[i]>maxx)
        {
            cnt=0;
            vis[++cnt]=i;
            maxx=a[i];
        }
        else if(a[i]==maxx)
        {
            vis[++cnt]=i;
        }
    }
    int t=0;
    for(int i=pos[x-1]+1;i<=pos[x];i++)
    {
        if(a[i]==maxx)
            t++;
    }
    if(t!=1&&t==pos[x]-pos[x-1])
        return 0;
     //第二次调用solve 函数时候的输出:   
    if(op==1)
    {
        int bt;
        int l=1,r=1;
        
//判断哪个最大位置可以走,如果最大位置吃掉了任意一个数字,比如 3 3 1   第二个三吃掉1 就变成了最大的最大,因为即便之前有和他相同的,但是他+1必定比之前的大
        for(int i=1;i<=cnt;i++)
        {
//扫面左边和右边
            l=1,r=1;
            if(vis[i]==pos[x-1]+1||(vis[i]!=pos[x-1]+1&&vis[i]==vis[i-1]+1) )
                l=0;
            if(vis[i]==pos[x]||vis[i]==vis[i+1]-1  )
                r=0;
            if(l==1||r==1)
               {
                bt=vis[i];
                break;
               }
        }
//下面的步骤不要忘记脚标的改变,
        if(l==1)
        {
            //如果可以往左吃,先吃到最左再吃到最右,注意输出的位置
            for(int i=bt;i>pos[x-1]+1;i--)
            {
                printf("%d ",i-all);//当前位置 
                printf("L\n");
            }
            for(int i=bt;i<pos[x];i++)
            {
                printf("%d ",pos[x-1]+1-all);//一直是最左
                printf("R\n");
            }
        }
        else if(r==1)//和最左相同,各位自己寻思下。
        {
            for(int i=bt;i<pos[x];i++)
            {
                printf("%d ",bt-all);
                printf("R\n");
            }
            for(int i=bt;i>pos[x-1]+1;i--)
            {
                printf("%d ",i-all);
                printf("L\n");
            }
        }
    }
    return 1;
}
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    int k;
    cin>>k;
    for(int i=1;i<=k;i++)
        {
            scanf("%d",&need[i]);
        }
    int sum=0;
    int cnt=1;
    int over=0;
    int i;
    //下面的一步,如果不能组合成要求的数字就结束。
    for( i=1;i<=n;i++)
    {
        sum+=a[i];
        if(sum==need[cnt])
        {
            pos[cnt]=i;
            sum=0;
            cnt++;
        }
        else if(sum>need[cnt])
        {
            over=1;
            break;
        }
    }
    pos[0]=0;
    if(i!=n+1||cnt!=k+1)
        over=1;
    if(over)
        printf("NO\n");
    if(over==0)
    {
        //下面的一步,如果可以组合成,但是不满足可以互相吃掉的要求 就比如 2 2 2 可以构成6 但是实际上不可以互相吃掉就跳出
        //详情见solve函数
        for( i=1;i<=k;i++)
        {
            if(solve(i,0)==0)
            {
                over=1;
                break;
            }
        }
        if(over)
        {
            printf("NO\n");
        }
        else
        {
            printf("YES\n");
            all=0;
            //都已经判断OK了。输出
            //注意all数字是改脚标值的。
            for( i=1;i<=k;i++)
            {
                solve(i,1);
                all+=pos[i]-pos[i-1]-1;
            }
        }
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值