CSPT2补全-2

201812-2小明放学
在这里插入图片描述
这道题的重点题目中已经加粗提示我们了,这里的秒数指的是小明出发的时刻的秒数,因此我们需要根据小明放学路上走到当前红绿灯位置经过的时间来判断此处红绿灯现在是什么颜色。
灯是按照绿黄红变化的,此刻是绿灯可以直接通过,此刻是黄灯需要等到黄灯剩余秒数跑完再等待一整个红灯,此刻是红灯需要等待红灯的剩余秒数。
实时更新小明到一个地点时所花费的时间,拿这个时间来判断灯的状态。此处仅详细说明经过时间大于剩余秒数的情况,首先将总时间减去剩余秒数,让当前的灯跑完。将减去后得到的时间对红绿黄三种信号灯时间总和取模,根据得到的结果落在的区间判断当前灯的颜色。

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

int main()
{
    int r,y,g;
    scanf("%d%d%d",&r,&y,&g);
    int n=0;
    scanf("%d",&n);
    ll cnt=0;

    int sum=r+y+g;
    
    for(int i=1;i<=n;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);

        if(a==0)//直接通过一段路
        cnt+=b;
        else if(a==1)
        {
            if(cnt<b)
            cnt+=b-cnt;
            else
            {
                ll lef=cnt-b;
                lef%=sum;
                if(lef<=g)
                cnt+=0;
                else if(lef>g&&lef<=g+y)
                cnt+=sum-lef;
                else if(lef>g+y)
                cnt+=sum-lef;
            }
        }
        else if(a==2)
        {
            if(cnt<b)
            cnt+=b-cnt+r;
            else
            {
                ll lef=cnt-b;
                lef%=sum;
                if(lef<=r)
                cnt+=r-lef;
                else if(lef>r&&lef<=r+g)
                cnt+=0;
                else if(lef>r+g)
                cnt+=sum-lef+r;
            }
        }
        else if(a==3)
        {
            if(cnt<b)
            cnt+=0;
            else
            {
                ll lef=cnt-b;
                lef%=sum;
                if(lef<=y)
                cnt+=y-lef+r;
                else if(lef>y&&lef<=y+r)
                cnt+=y+r-lef;
                else if(lef>y+r)
                cnt+=0;
            }
        }
       
    } 
    printf("%lld",cnt);
}

201803-碰撞的小球
在这里插入图片描述
最开始的时候我对这道题毫无头绪,去csdn上搜了几个题解好像都用了什么数学变化将这个运动过程简化,但是我看不懂。其中一篇文章说用模拟法会更加简单,我看了一下数据范围,感觉不是很大,用直线条的方法说不定可以,于是尝试了一下,发现还是OK的。
我对球的模拟的前提是每个球只会和相邻的两个球相撞,因为两个球相撞以后彼此都会掉头,不存在某个球越过它两边的球的情况。直接做的话想法很简单,每一秒就重新计算所有球的位置,同时看它是不是和左右两边球的坐标相同,相同代表相撞,改变记录球方向的数组。计算位置需要根据球的方向来进行加减。

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

pair<int,int> pos[110];//由于输入不是按坐标顺序,需要存储球的标号及坐标
int fl[110];//记录最终结果
bool goright[110];//球的方向

int main()
{
    int n,l,t;
    scanf("%d%d%d",&n,&l,&t);

    for(int i=1;i<=n;i++)
    {
        int x=0;
        scanf("%d",&x);
        goright[i]=true;//一开始所有的球都向右运动
        pos[i].first=x;
        pos[i].second=i;
    }

    sort(pos,pos+n+1);//根据球的坐标排序

    for(int tt=1;tt<=t;tt++)
    {
        for(int b=n;b>=1;b--)
        {
            if(goright[b])//向右运动坐标加
            pos[b].first++;
            else
            pos[b].first--;//向左运动坐标减
        }

        for(int b=n;b>=1;b--)
        {
            if(pos[b].first==l)//判断是否碰壁
            {
                goright[b]=false;
                continue;
            }
            
            if(pos[b].first==0)
            {
                goright[b]=true;
                continue;
            }

            if(b>1)//判断小球间是否相撞
            {
                if(pos[b].first==pos[b-1].first)
                {
                    goright[b]=!goright[b];//掉头
                }
            }
            if(b<n)
            {
                if(pos[b].first==pos[b+1].first)
                {
                    goright[b]=!goright[b];
                }
            }
        }
    }

    for(int i=1;i<=n;i++)
    {
        fl[pos[i].second]=pos[i].first;//提取答案
    }

    for(int i=1;i<=n;i++)
    printf("%d ",fl[i]);
}

需要注意的是并不是按照坐标顺序输出的,而是根据小球的标号输出,这里可能不注意会出错
这道题给我的启发也许就是,有时候可以试试照着题目的意思写写试试,不一定是行不通的。特别是在没有别的思路的时候,总比放空要好吧。
201709-2公共钥匙盒
钥匙进出公共钥匙盒的主要规则是,同时借还时先还再借,同时还时钥匙序号小的先还,优先从左边开始挑选空闲的位置还钥匙。
那么我们需要同时记录借还动作发生的时间以及钥匙的标号。按照时间排序可以自动地进行借还操作,只需要考虑几个问题,第一,如何区分借钥匙和还钥匙,第二,如何保证先还后借,第三,如何保证标号小的钥匙先还。
我的想法是在基础的钥匙标号上加一个足够大的数,不可能有正常的钥匙标号在这个数区间内,当我们发现钥匙标号足够大时,说明这个操作是借钥匙,减去基数后得到真正的钥匙标号。时间顺序又优于借还顺序,我们可以想到pair,优先根据第一关键字排序,第一关键字相同根据第二关键字排序,第一关键字是时间的前提下,如果时间相同,优于借钥匙已经被加上足够大的基数,其排序一定在还钥匙之后,这样就可以保证顺序。

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

int key[1010];//每个位置放的是什么钥匙
set<pair<int,int>> timer;//所有的操作
map<int,int> pos;//每个钥匙的位置

int main()
{
    int n,k;
    scanf("%d%d",&n,&k);

    for(int i=1;i<=n;i++)
    {
        key[i]=i;//最开始所有钥匙都在对应的位置
        pos[i]=i;
    }

    while(k--)
    {
        int w,s,c;
        scanf("%d%d%d",&w,&s,&c);
        timer.emplace(s,w+100000);
        timer.emplace(s+c,w);
    }

    for(auto it=timer.begin();it!=timer.end();it++)
    {
        int y=it->second;
        if(y<100000)//还钥匙
        {
            for(int i=1;i<=n;i++)
            {
                if(key[i]==0)//找到一个空闲位置
                {
                    key[i]=y;
                    pos[y]=i;
                    break;
                }
            }
        }
        else
        {
            key[pos[y-100000]]=0;//取走钥匙
            pos[y-100000]=-1;
        }
    }

    for(int i=1;i<=n;i++)
    printf("%d ",key[i]);
}

201609-2火车购票
在这里插入图片描述
这道题的我做的也挺硬的,开一个set数组,记录每一行的空座,然后就是先搜索有没有连座,没连座就按小的来,卖完票以后把卖出去的座位从每一行踢出去。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值