题目大意
有一个长度为 \(L\) 的环 \((2 \le L \le 10^9)\),
环上有 \(n\) 个人, \(m\) 个出口 \((1 \le n,m \le 2 \times 10^5)\).
规定第一个出口的位置为 \(0\), 并将 "到第一个出口的距离" 定义为 "从顺时针方向走到第一个路口所走的路程".
每个人有两个属性 \(t_i,\ x_i\), 分别表示这个人的前进方向 (\(0\) 为逆时针, \(1\) 为顺时针), 以及这个人到第一个出口的距离.
每个出口有两个属性 \(lim_i,\ a_i\), 分别表示这个出口的人数限制 (即最多能从这个出口出去多少人), 以及这个出口到第一个出口的距离.
在每个单位时间内, 所有人都会朝着他们的前进方向移动一个单位距离,
若有一个人 \(i\) 走到了一个人数没有达到上限的出口 \(j\), 他就会从这个出口出去, 则 \(k[i]=j\).
特别地, 若有两个人同时到达了一个只能出去一个人的出口, 则编号较小的那个人可以出去.
最终输出 \(i \times k[i]\) 的异或和, 即
\[ (1 \times k[1]) \oplus (2 \times k[2]) \oplus \dots \oplus (n \times k[n])\]
(注: \(\oplus\) 为异或符号)
思路
\(O(n^2)\) 52pts
首先, 最暴力的思路就是大模拟, 每次把每一个人往他的移动方向移一格, 然后从小到大扫一遍, 看哪个人可以出去.
可以发现, 我们其实只需要找到离他下一个出口最近的那个人, 记他离出口的距离为 \(mind\), 把所有人往前移动 \(mind\) 个单位距离就行了.
当然, 有可能出现这个人到了出口后, 发现出口已经被填满了, 那么我们就需要再去找他的下一个出口, 而这是一个最劣能达到 \(O(n)\) 的操作, 这样的话复杂度就有可能退化到 \(O(n^3)\).
所以, 我们需要用(双向的)并查集优化一下这个过程, 总复杂度为 \(O(\alpha n^3)\).
但还要注意的是, 不是每一次都能使得至少有一个人出去, 因为当前离出口最近的那个人他指向的出口已经被填满了, 所以复杂度应该是 \(O(玄学 \times \alpha n^3)\)
代码在下面.
代码
\(O(n^2)\) 52pts
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+7;
const int inf=0x3f3f3f3f;
int n,m,L,d[N],nxt[N],le[N],ri[N],ans,a[N],x[N],minx=inf,nm,nn,lim[N];
bool t[N],gon[N];
int exi[N];
int dis(int i,int j){
if(!j) return inf;
int di=abs(x[i]-a[j]);
if((a[j]>x[i]&&t[i])||(a[j]<x[i]&&!t[i])) di=L+1-di;
return di;
}
int fl(int x){ return le[x]==x ?x :le[x]=fl(le[x]); }
int fr(int x){ return ri[x]==x ?x :ri[x]=fr(ri[x]); }
int main(){
\\freopen("walk.in","r",stdin);
\\freopen("walk.out","w",stdout);
cin>>n>>m>>L;
for(int i=2;i<=m;i++){
scanf("%d",&a[i]);
le[i]=ri[i]=i;
}
le[1]=ri[1]=1;
for(int i=1;i<=m;i++) scanf("%d",&lim[i]);
for(int i=1;i<=n;i++){
scanf("%d%d",&t[i],&x[i]);
for(int j=1;j<=m;j++)
if(dis(i,j)<dis(i,nxt[i])) nxt[i]=j;
minx=min(minx,dis(i,nxt[i]));
}
while(nm<m&&nn<n){
int mind=minx; minx=inf;
for(int i=1;i<=n;i++){
if(gon[i]) continue;
if(t[i]) x[i]-=mind;
else x[i]+=mind;
if(x[i]<0) x[i]+=L+1;
else if(x[i]>L) x[i]-=L+1;
if(x[i]==a[nxt[i]]){
if(!lim[nxt[i]]){
int tmp=0;
while(!lim[nxt[i]]){
if(t[i]){ le[tmp]=nxt[i]; nxt[i]=fl(nxt[i])-1; }
else{ ri[tmp]=nxt[i]; nxt[i]=fr(nxt[i])+1; }
if(!nxt[i]) nxt[i]=m;
if(nxt[i]>m) nxt[i]=1;
tmp=nxt[i];
}
}
else{
lim[nxt[i]]--;
if(!lim[nxt[i]]) nm++;
gon[i]=1; nn++;
ans^=i*nxt[i];
exi[i]=nxt[i];
}
}
if(!gon[i]) minx=min(minx,dis(i,nxt[i]));
}
}
printf("%d\n",ans);
//for(int i=1;i<=n;i++) printf("%d ",exi[i]); putchar('\n');
return 0;
}