【题解】「BZOJ5079」

题目描述
你在一个秘密据点门口安装了监控探头,希望监控人员出入情况。

探头记录了据点某天从早到晚的人员进出情况,你不知道据点内开始的人数。

同时,进出据点的人可能会进行伪装,你无法从探头记录中得知伪装的人的身份。探头的每条记录是以下两个形式之一:

E id
当 id>0 时,表示编号为 id 的人进入了这个据点; 当 id 为 0 时,表示一个伪装的人进入了据点。

L id
当 id>0 时,表示编号为 id 的人离开了这个据点; 当 id 为 0 时,表示一个伪装的人离开了据点。

你想弄清楚,这个据点是不是一定有其他出入口,如果没有的话,当一天结束时,待在据点里的人的最少可能数量是多少。

n<=1000

solution:

很有难度 。

二分在开头添加多少个 E 0 。

对于 E 0 的情况,如果有一个当前不在据点的人,下一个事件是离开,选择满足以上两个条件中最早的人。

否则分配为任意从未出现过的人的编号。

对于 L 0 的情况,如果有一个人当前在据点,下一个事件是进入,选择满足以上两个条件中最早的人。

否则如果存在一个人在据点内,且后续没有操作,随便选择一个这样的人离开。

如果找不到满足前两者的情况,说明据点内所有人的下一个操作都是离开,选择最晚离开的编号。

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define fi first
#define se second
#define db double
using namespace std;
const int Maxn=3005;
int n,id[Maxn],now[Maxn],tmp[Maxn];
char s[Maxn][2];
int askin(int l) {
	//如果有一个当前不在据点的人,下一个事件是离开,选择满足以上两个条件中最早的人
	for(int i=1;i<=2005;i++) tmp[i]=now[i];
	for(int i=l;i<=n;i++) {
		if(id[i]&&!tmp[id[i]]&&s[i][0]=='L') {
			return id[i];
		}
		tmp[id[i]]=1;
	}
	//否则分配为任意从未出现过的人的编号
	for(int i=1;i<=2005;i++) {
		if(!tmp[i]) {
			return i;
		}
	} 
}
int askout(int l) {
	for(int i=1;i<=2005;i++) tmp[i]=now[i];
	//如果有一个人当前在据点,下一个事件是进入,选择满足以上两个条件中最早的人
	for(int i=l;i<=n;i++) {
		if(id[i]&&tmp[id[i]]&&s[i][0]=='E') {
			return id[i];
		}
		tmp[id[i]]=0;
	} 
	//否则如果存在一个人在据点内,且后续没有操作,随便选择一个这样的人离开
	for(int i=1;i<=2005;i++) {
		if(tmp[i]==1) {
			return i;
		}
	} 
	//如果找不到满足前两者的情况,说明据点内所有人的下一个操作都是离开,选择最晚离开的编号 
	for(int i=1;i<=2005;i++) tmp[i]=now[i];
	int kth=-1;
	for(int i=l;i<=n;i++) {
		if(id[i]&&tmp[id[i]]&&s[i][0]=='L') {
			kth=id[i];
		}
		tmp[id[i]]=0;
	} 
	return kth;
}
bool ok(int l) {
	for(int i=1;i<=2005;i++) now[i]=0;
	for(int i=l;i<=n;i++) {
		if(id[i]) {
			if(s[i][0]=='E') {
				if(now[id[i]]) {
					return 0;
				}
				now[id[i]]=1;
			}
			else {
				if(!now[id[i]]) {
					return 0;
				}
				now[id[i]]=0;
			}
		}
		else {
			if(s[i][0]=='E') {
				int y=askin(i+1);
				now[y]=1;
			}
			else {
				int y=askout(i+1);
				if(y==-1) return 0;
				now[y]=0;
			}
		}
	}
	return 1;
}
int main() {
//	freopen("data.in","r",stdin);
	int T;
	scanf("%d",&T);
	for(int i=1;i<=1005;i++) {
		s[i][0]='E';
	}
	while(T--) {
		scanf("%d",&n);
		for(int i=1;i<=n;i++) {
			scanf("%s%d",s[i+1005],&id[i+1005]);
		}
		n+=1005;
		int l=1,r=1006;
		while(l<r) {
			int mid=l+r+1>>1;
			if(ok(mid)) {
				l=mid;
			}
			else {
				r=mid-1;
			}
		} 
		if(l==1) {
			printf("OTHER\n");
		}
		else {
			int ans=0;
			for(int i=l;i<=n;i++) {
				if(s[i][0]=='E') {
					ans++;
				}
				else {
					ans--;
				}
			}
			printf("%d\n",ans);
		}
	}
	
}
posted @ 2021-09-14 16:04  仰望星空的蚂蚁  阅读(8)  评论(0)    收藏  举报  来源