AT_arc101_d [ARC101F] Robots and Exits 题解--zhengjun
思路不错。
首先考虑把每个机器人转化为 \((a_i,b_i)\) 两个参数。
表示向左 \(a_i\) 步会进入左边的出口,向右 \(b_i\) 会进入右边的出口。
注:此时其他只能进入唯一的出口的机器人不影响答案,不考虑。
记 \(c_i=0/1\) 表示 \(i\) 号机器人是进入左边还是右边出口。
然后考虑不同机器人进入出口的限制:
对于 \(i,j\),若 \(a_i < a_j, b_i >b_j\),那么:
\[c_i=1 \Longrightarrow c_j=1\\
c_j=0\Longrightarrow c_i=0
\]
考虑把机器人放到坐标 \((a_i,b_i)\) 上面。
然后有一个格子,其左下角坐标为 \((x,y)\) 表示当前移动向左最大为 \(x\),向右最大为 \(y\)。
那么 该格子 每次会向上或向右走一格,发现如果该格子移动到了 \((a_i,b_i)\) 的左上方,说明该机器人进入左边出口,如果移动到了右下方,那么进入右边出口。
然后,发现限制就形象地被化解了,只需要走格子就行了。
计算从 \((0,0)\) 走到 \((+\infty,+\infty)\) 的方案数(两种方案不同当且仅当存在 \(i\) 满足两个方案从 \((a_i,b_i)\) 的不同侧绕过)。
注意 \((a_i,b_i)\) 需要去重。
这个问题可以看看加强版:CF720D Slalom
直接扫描线维护即可。
代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=1e5+10,mod=1e9+7;
int n,m,k,p[N],q[N];
struct zj{
int x,y;
}a[N];
vector<int>o[N];
int c[N];
void add(int x,int y){
for(;x<=m+1;x+=x&-x)(c[x]+=y)%=mod;
}
int get(int x,int y=0){
for(;x;x^=x&-x)(y+=c[x])%=mod;
return y;
}
void print(){
for(int i=1;i<=m+1;i++)printf("%d%c",(get(i)-get(i-1)+mod)%mod,"\n "[i<=m]);
}
int main(){
freopen(".in","r",stdin);
//freopen(".out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&p[i]);
for(int i=1;i<=m;i++)scanf("%d",&q[i]);
for(int i=1,x=1;i<=n;i++){
for(;x<=m&&q[x]<p[i];x++);
if(x>1&&x<=m)a[++k]={p[i]-q[x-1],q[x]-p[i]};
}
if(!k)return puts("1"),0;
n=m=0;
for(int i=1;i<=k;i++)p[++n]=a[i].x,q[++m]=a[i].y;
sort(p+1,p+1+n),n=unique(p+1,p+1+n)-p-1;
sort(q+1,q+1+m),m=unique(q+1,q+1+m)-q-1;
for(int i=1;i<=k;i++)a[i].x=lower_bound(p+1,p+1+n,a[i].x)-p;
for(int i=1;i<=k;i++)a[i].y=lower_bound(q+1,q+1+m,a[i].y)-q;
for(int i=1;i<=k;i++)o[a[i].x].push_back(a[i].y);
// for(int i=1;i<=k;i++)fprintf(stderr,"%d %d\n",a[i].x,a[i].y);
add(1,1);
// print();
for(int i=1;i<=n;i++){
sort(o[i].begin(),o[i].end(),greater<int>());
o[i].erase(unique(o[i].begin(),o[i].end()),o[i].end());
for(int x:o[i])add(x+1,get(x));
// print();
}
cout<<get(m+1);
return 0;
}