【题解】「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);
}
}
}

浙公网安备 33010602011771号