Kick Start 2019 Round D Latest Guests 队列

Problem

The city of Circleburg has a large circular street with N consulates along it. The consulates are numbered 1, 2, ..., N in clockwise order.

Today G guests, numbered 1, 2, ..., G will drive along the circular street for M minutes. Each guest is either a clockwise guest (denoted by the character C) or an anti-clockwise guest (denoted by the character A).

The i-th guest starts at the consulate numbered Hi and at the end of each minute will drive to an adjacent consulate. The i-th guest starts at the j-th consulate. If that guest is:

  • a clockwise guest, they will drive to the (j+1)-th consulate (unless they are at the N-th consulate, then they will drive to the 1st consulate).
  • an anti-clockwise guest, they will drive to the (j-1)-th consulate (unless they are at the 1st consulate, then they will drive to the N-th consulate).

Each consulate will only remember the guest that visited them last. If there are multiple guests who visited last, then the consulate will remember all of those guests.

For each guest, determine how many consulates will remember them.

Input

The first line of the input gives the number of test cases, TT test cases follow. Each testcase begins with a line containing the three integers NG and M, which are the number of consulates, the number of guests and the number of minutes respectively. Then, G lines follow. The i-th line contains the integer Hi followed by a single character; C if the i-th guest is a clockwise guest or A if the i-th guest is an anti-clockwise guest.

Output

For each test case, output one line containing Case #x: y1 y2 ... yG, where x is the test case number (starting from 1) and yi is the number of consulates that remember the i-th guest.

Limits

Time limit: 15 seconds per test set.
Memory limit: 1GB.
1 ≤ T ≤ 100.
1 ≤ Hi ≤ N, for all i.

Test set 1 (Visible)

2 ≤ N ≤ 100.
1 ≤ G ≤ 100.
0 ≤ M ≤ 100.

Test set 2 (Hidden)

2 ≤ N ≤ 105.
1 ≤ G ≤ 105.
0 ≤ M ≤ 109.

Sample


Input 
 

Output 
 
4
5 3 2
5 C
2 A
1 A
2 4 0
1 A
1 C
1 A
1 C
3 2 10
3 C
2 A
6 1 6
4 A

  
Case #1: 2 2 1
Case #2: 1 1 1 1
Case #3: 2 2
Case #4: 6

  

In the first sample case, there are N = 5 consulates, G = 3 guests, who will drive for M = 2 minutes.

  • For the 1st consulate, it is last visited by guests 1 and 2 (at the end of the 1st minute).
  • For the 2nd consulate, it is last visited by guest 1 (at the end of the 2nd minute).
  • The 3rd consulate, is never visited.
  • For the 4th consulate, it is last visited by guest 3 (at the end of the 2nd minute).
  • For the 5th consulate, it is last visited by guest 2 (at the end of the 2nd minute).

Thus the answer should be 2, 2, 1 for the 1st, 2nd and 3rd guests respectively.

In the second sample case, there are N = 2 consulates, G = 4 guests, who will drive for M = 0 minutes.

  • For the 1st consulate, it is last visited by guests 1, 2, 3 and 4 (all the guests start at this consulate).
  • The 2nd consulate, is never visited.

Thus the answer should be 1, 1, 1, 1 for the 1st, 2nd, 3rd and 4th guests respectively.

In the third sample case, there are N = 3 consulates, G = 2 guests, who will drive for M = 10 minutes.

  • For the 1st consulate, it is last visited by guests 1, and 2 (at the end of the 10th minute).
  • For the 2nd consulate, it is last visited by guest 2 (at the end of the 9th minute).
  • For the 3rd consulate, it is last visited by guest 1 (at the end of the 9th minute).

Thus the answer should be 2, 2 for the 1st and 2nd guests respectively.

In the fourth sample case, there is only one guest. This guest visits all the consulates eventually, so is remembered by all of them. Thus the answer is 6.

 

 

思路: 首先不难想到, 如果m>=2*n, 那么除了第一次走n步,其余的走n步都是对第一次过程的重复,所以如果m>=2*n,则m=n+(m%n).这样m就缩小到1e5级别了.

我们先看顺时针的情况: 对于某一个点i,谁会经过它? 肯定是从i往逆时针走m步,若路过的点上有人,那么这个人肯定会经过点i. 那么谁会最后一个经过i? 肯定是走m步/最后遇到的/有人的那个点/上的人(有点绕口,已断句). 那么对于点i,我们维护一个往前走m步的一个队列,若队列不为空,那么队列的front就是最后一个经过i的人. 对于i+1来说,我们只需要看队列首部那个人的位置是不是距离(i+1)超过了m,如果超过了m则将其pop掉即可;然后再看i+1这个点是否存在顺时针走的人,若存在则将其push到队列尾部即可.

逆时针类似.

上很sb的代码... 为了方便读懂我加点注释吧

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <string>
#include <queue>
#include <cmath>
#include <stack>
#include <time.h>
#include <map>
#include <set>
#define mem(a,x) memset(a,x,sizeof(a))
#define gi(x) scanf("%d",&x)
#define gi2(x,y) scanf("%d%d",&x,&y)
#define gi3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define gll(x) scanf("%lld",&x)
#define gll2(x,y) scanf("%lld%lld",&x,&y)
using namespace std;
const double eps=1e-8; 
typedef long long ll;
const int MAXN=200005;
const ll mod=1e9+7;
const int inf=0x3f3f3f3f;
vector<int>a[2][MAXN];//0 is clockwise , 1 is anti-clockwise
int book[MAXN];//book[i]代表最后经过i号地点的人的下标(原位置的下标)
int book1[MAXN];//若某个地点同时被瞬时间和逆时针的人最后经过,用book[i]记录瞬时间,book1[i]记录瞬时间
int flag[MAXN];//flag[i]=-1,0,1,2 分别代表没有人经过i,最后经过是瞬时间的,最后经过是逆时针的,最后是瞬时间和逆时针同时经过的
int s[MAXN];//逆时针的队列
int num[2][MAXN];//num[0][i]代表最初在i号点且顺时针方向行驶的人 最后经过了多少个地点 num[1][i]代表逆时针
int n,g,m;
int ss[MAXN];//ss[i]代表标号为i的人 最后经过了ss[i]个地点
queue<int>q;//瞬时针的队列
int dis(int a,int b){
	if(a<=b){
		return b-a;
	}
	else{
		return n-a+b;
	}
}
void init(){
	while(!q.empty())q.pop();
	for(int i=1;i<=n;i++){
		num[0][i]=num[1][i]=0;
		a[0][i].clear();
		a[0][i+n].clear();
		a[1][i].clear();
		a[1][i+n].clear();
		book[i]=-1;
		book1[i]=-1;
		flag[i]=0;
	}
	if(m>=2*n){
		m%=n;
		m+=n;
	}
}
int main(){
	
	int T,cnt=1;
	gi(T);
	while(T--){
		printf("Case #%d:",cnt++);
		int l=1,r=0;
		gi3(n,g,m);//n 不是乘客
		init();
		for(int i=1;i<=g;i++){
			ss[i]=0;
			int x;char s1[3];
			gi(x);scanf("%s",s1);
			if(s1[0]=='C'){
				a[0][x].push_back(i);
				a[0][x+n].push_back(i);
			}
			else{
				a[1][x].push_back(i);
				a[1][x+n].push_back(i);
			}
		}
		n*=2;//把1-n复制成两段
		for(int i=n-m+1;i<=n;i++){
			if(a[0][i].size()){
				q.push(i);
			}
		}
		if(a[0][1].size()){
			q.push(1);
		}
		for(int i=1;i<=m+1;i++){
			if(a[1][i].size()){
				++r;
				s[r]=i;
			}
		}
		for(int i=1;i<=n/2;i++){
			if(i!=1){//更新队列
				while(!q.empty()&&(dis(q.front(),i)>m||q.front()==i)){
					q.pop();
				}
				if(a[0][i].size()){
					q.push(i);
				}
				int nx=i+m;
				if(nx>n)nx-=n;
				if(a[1][nx].size()){
					++r;
					s[r]=nx;
				}
			}
			if(q.empty()&&l>r){//都为空,没人经过此点
				flag[i]=-1;
				book[i]=-1;
			}
			else if(q.empty()){//逆时针不为空
				flag[i]=1;
				book[i]=s[r];
			}
			else if(l>r){//顺时针不为空
				flag[i]=0;
				book[i]=q.front();
			}
			else{//瞬时间和你时间都不为空
				int t1=dis(q.front(), i);
				int t2=dis(i,s[r]);
				if(t1==t2){//距离相等,则都要记录
					flag[i]=2;
					book[i]=q.front();
					book1[i]=s[r];
				}
				else if(t1>t2){//瞬时间离得更远,则瞬时间最后经过
					flag[i]=0;
					book[i]=q.front();
				}
				else{//逆时针离得更远,则逆时针最后经过
					flag[i]=1;
					book[i]=s[r];
				}
			}
			if(l<=r&&s[l]==i){//更新队列, 如果逆时针队列里有i,要计算i+1时,当然要把i删除
				l++;
			}
		}
		n/=2;
		for(int i=1;i<=n;i++){
			if(flag[i]==0||flag[i]==1){
				int t=book[i];
				while(t>n)t-=n;
				num[flag[i]][t]++;
			}
			else if(flag[i]==2){
				int t=book[i];
				while(t>n)t-=n;
				num[0][t]++;
				
				t=book1[i];
				while(t>n)t-=n;
				num[1][t]++;
			}
		}
		for(int i=0;i<=1;i++){
			for(int j=1;j<=n;j++){
				for(int q=0;q<a[i][j].size();q++){
					int id=a[i][j][q];
					ss[id]+=num[i][j];
				}
			}
		}
		for(int i=1;i<=g;i++){
			printf(" %d",ss[i]);
		}
		puts("");
	}
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值