(LR机器人爆炸)CF1525C(括号匹配)

题目

CF1525C :点这里
题目大意:给定n,m,其中n代表机器人,m代表边界,每个机器人有方向L,R,走到同一位置上面会爆炸,走到0或边界m上面,下一秒会改变方向返回,最后输出每个机器人爆炸的时间

算法思路

  1. 括号匹配思路,用堆栈来做,L相当于右括号,R相当于左括号,对撞相当于匹配
  2. 只有坐标的奇偶性相同,才有可能对撞,因为同向移动,距离改变0,异向移动,距离改变为-2或+2,奇偶性永远不会改变,所以只需要针对奇偶性,分开处理坐标为奇数,和坐标为偶数的即可
  3. 将坐标按照从小到大排序一遍,然后i从1到n开始处理,但是要记录原来的爆炸时间,所以每个结构体还得带上一个成员变量id
  4. 如果是R(左括号)则直接入栈,
  5. 如果是L(右括号),则查看栈中是否有东西
  6. 如果东西,则取出栈顶,对撞输出二者的答案,ans[a[i].id]=ans[a[stk1[top1]].id]=(a[i].x-a[stk1[top1]].x)/2,二者之间的距离除以二
  7. 如果没有东西,代表L(右括号)会变成R(左括号),此时分享改变后的x坐标相当于镜像,即a[i].x=-a[i].x
  8. 栈中最后可能还有剩余东西,即全部都是R(左括号),这种情况,栈顶的元素又会反转成为L(右括号),栈中的top和top-1个元素会抵消,所以答案为ans[a[stk1[top1]].id]=ans[a[stk1[top1-1]].id]=(2*(m-a[stk1[top1]].x)+a[stk1[top1]].x-a[stk1[top1-1]].x)/2
  9. 最后每个奇偶性的栈里面,最多只剩下一个机器人,那么这个机起人永远不会爆炸,这个时候我们就可以在初值的地方全部赋值为-1

代码实现

#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
#define el '\n'
#define cl putchar('\n')
#define pb push_back
#define eb emplace_back
#define fir first
#define sec second


typedef long long ll;
typedef pair<int,int> pii;
typedef vector<int> vci;
typedef map<int,int> mii;
typedef mii::iterator mii_it;

const int N=3e5+10,M=1e3+10;

struct node{
   int x,id;
   char b;
}a[N];
int ans[N],stk1[N],stk2[N],top1,top2;
int cmp(node x,node y){
   return x.x<y.x;
}

int T,n,m;

int main() {
   cin.tie(0);
   cout.tie(0);

   cin>>T;
   while(T--) {
   	cin>>n>>m;
   	top1=top2=0;
   	memset(ans,-1,sizeof(ans));
   	for(int i=1; i<=n; i++) {
   		cin>>a[i].x;
   		a[i].id=i;
   	}
   	for(int i=1; i<=n; i++)cin>>a[i].b;
   	sort(a+1,a+n+1,cmp);

   	for(int i=1; i<=n; i++) {
//			cout<<"#";
//			for(int j=1;j<=top1;j++){
//				cout<<stk1[j]<<' ';
//			}
//			cl;
//			for(int j=1;j<=top2;j++){
//				cout<<stk2[j]<<' ';
//			}
//			cl;
   		if(a[i].x%2==0) {
   			if(a[i].b=='L') {
   				if(top1>0) {
   					ans[a[i].id]=ans[a[stk1[top1]].id]=(a[i].x-a[stk1[top1]].x)/2;
   					top1--;
   				} else {
   					stk1[++top1]=i;
   					a[i].x=-a[i].x;
   				}
   			} else {
   				stk1[++top1]=i;
   			}
   		}
   		else {
   			if(a[i].b=='L') {
   				if(top2>0) {
   					ans[a[i].id]=ans[a[stk2[top2]].id]=(a[i].x-a[stk2[top2]].x)/2;
   					top2--;
   				} else {
   					stk2[++top2]=i;
   					a[i].x=-a[i].x;
   				}
   			} else {
   				stk2[++top2]=i;
   			}
   		}
   	}
   	while(top1>=2) {
   		ans[a[stk1[top1]].id]=ans[a[stk1[top1-1]].id]=(2*(m-a[stk1[top1]].x)+a[stk1[top1]].x-a[stk1[top1-1]].x)/2;
   		top1-=2;
   	}
   	while(top2>=2) {
   		ans[a[stk2[top2]].id]=ans[a[stk2[top2-1]].id]=(2*(m-a[stk2[top2]].x)+a[stk2[top2]].x-a[stk2[top2-1]].x)/2;
   		top2-=2;
   	}
   	for(int i=1;i<=n;i++){
   		cout<<ans[i]<<" ";
   	}
   	cl;
   }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值