CF1525C Robot Collisions

博客主要探讨了在数轴上机器人碰撞的问题。机器人按设定方向行走,遇到边界会立即掉头。若两个机器人在同一整数点相遇则碰撞消失。文章指出只有奇偶性相同的机器人会相撞,并通过奇偶性分类简化问题。接着,通过栈实现括号匹配方法处理相对的机器人,最终解决所有可能的碰撞情况。如果最后剩下1个或2个机器人,根据它们的朝向确定相撞时刻。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门

题目大意

在一条数轴上有 n n n 个机器人,每个机器人有一个初始的朝向,之后每一秒,它会向着它朝向的方向走一个单位,如果到达了 0 0 0 或者 m m m 那么就会立即掉头。如果多个机器人在同一整数点相遇,那么它们就会碰撞炸掉,在此之后就不会与其他机器人碰撞了。现需要你求出每个机器人最早在第几时刻炸掉,如果不会,则输出 -1

Solution

首先是注意一点:当且仅当两个机器人奇偶性相同时才会相撞,并且没有意外是一定会相撞的。

可以很简单地证一下,每一次移动每一个机器人的位置奇偶性都会改变,如果两个机器人的奇偶性不同,那么任意时刻其奇偶性都是不同的,也就不可能同时在一个整数点相遇了。

所以我们可以对每个点进行奇偶分类。

然后对于每组,我们考虑机器人相撞,可以发现如果两个机器人是相对的并且中间没有其他机器人,那么必定是这两个机器人相撞……等等,这不就是括号匹配么。所以用一个栈维护一下就可以把所有相对的机器人处理掉,最后只剩下:L...LR...R 这样的朝向,此时,我们对两边分别进行处理,对于向左的,最左边转向后必定和左边第二个相撞,左边第三个必定转向后和左边第四个相撞……右边也是同理。

这样处理完后,可能会剩下 1 1 1 个或者 2 2 2 个机器人,如果是 1 1 1 个,那么没有人与之相撞,则答案为 -1,否则,剩下 2 2 2 个朝向是这样的:LR,让它们两个走到头再转向回来相撞即可。

Code

#include<bits/stdc++.h>
#define ll long long
#define inf 1<<30
#define int long long
using namespace std;
const int MAXN=3e5+10;
struct node{
	int pos,id;
	char dir;
	node(){}
	node(int _pos,int _id,char _dir){
		pos=_pos;id=_id;dir=_dir;
	}
	bool friend operator<(node a,node b){
		return a.pos<b.pos;
	}
}odd[MAXN],eve[MAXN],bas[MAXN];
int stk[MAXN],top,ans[MAXN];
int bin[MAXN],hed;
void solve(){
	int n,m,ocnt=0,ecnt=0;
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%lld",&bas[i].pos),bas[i].id=i;
	for(int i=1;i<=n;i++)
		scanf(" %c",&bas[i].dir);
	sort(bas+1,bas+1+n);//记得排序
	for(int i=1;i<=n;i++){
		if(bas[i].pos&1) odd[++ocnt]=bas[i];
		else eve[++ecnt]=bas[i];
	}//奇偶分组
	
	top=0;hed=0;
	for(int i=1;i<=ocnt;i++){
		if(odd[i].dir=='R') stk[++top]=i;
		else{
			if(!top) bin[++hed]=i;//如果栈空,说明这个向左的是多出来的,存着就行
			else{
				int j=stk[top--];
				ans[odd[i].id]=ans[odd[j].id]=(odd[i].pos-odd[j].pos)/2;
			}
		}
	}//做括号匹配,把相对的消去,变成 L...LR...R 的形式
	for(int i=1;i<hed;i+=2){
		ans[odd[bin[i]].id]=ans[odd[bin[i+1]].id]=(odd[bin[i+1]].pos-odd[bin[i]].pos)/2+odd[bin[i]].pos;
	}//处理向左多出来的部分,两两相撞
	for(int i=top;i>1;i-=2){
		ans[odd[stk[i]].id]=ans[odd[stk[i-1]].id]=(odd[stk[i]].pos-odd[stk[i-1]].pos)/2+m-odd[stk[i]].pos;
	}//stk 中多出来的就是向右多余的,也是一样处理
	if(hed%2&&top%2){//如果两个都有 1 个剩余,那么把它们继续撞
		ans[odd[bin[hed]].id]=ans[odd[stk[1]].id]=(odd[bin[hed]].pos+m-odd[stk[1]].pos+m)/2;
	}else if(hed%2) ans[odd[bin[hed]].id]=-1;
	else if(top%2) ans[odd[stk[1]].id]=-1;//否则答案就是 -1
	/*                处理奇数                  */
	top=0;hed=0;
	for(int i=1;i<=ecnt;i++){
		if(eve[i].dir=='R') stk[++top]=i;
		else{
			if(!top) bin[++hed]=i;
			else{
				int j=stk[top--];
				ans[eve[i].id]=ans[eve[j].id]=(eve[i].pos-eve[j].pos)/2;
			}
		}
	}
	for(int i=1;i<hed;i+=2){
		ans[eve[bin[i]].id]=ans[eve[bin[i+1]].id]=(eve[bin[i+1]].pos-eve[bin[i]].pos)/2+eve[bin[i]].pos;
	}for(int i=top;i>1;i-=2){
		ans[eve[stk[i]].id]=ans[eve[stk[i-1]].id]=(eve[stk[i]].pos-eve[stk[i-1]].pos)/2+m-eve[stk[i]].pos;
	}if(hed%2&&top%2){
		ans[eve[bin[hed]].id]=ans[eve[stk[1]].id]=(eve[bin[hed]].pos+m-eve[stk[1]].pos+m)/2;
	}else if(hed%2) ans[eve[bin[hed]].id]=-1;
	else if(top%2) ans[eve[stk[1]].id]=-1;
	//和奇数完全一样
	/*                处理偶数                  */
	for(int i=1;i<=n;i++)
		printf("%lld ",ans[i]);
	printf("\n");
}
signed main()
{
	int T;
	for(scanf("%lld",&T);T--;)
		solve();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值