AT_arc101_d [ARC101F] Robots and Exits题解
sword7level · · 题解
题意:
题目是说有
题目分析:
首先我们考虑机器人不能跳过某个洞,那么很显然每个机器人只能从它坐标的相邻两个洞离开。我们可以先把只有一边有洞的机器人剔除,因为它们只有一种贡献。对于两边都有洞的机器人,设向左移出的状态为
这里需要注意,不能把两个机器人的限制静态地写成“若
对每个机器人
但同一个方案可能对应多条路径,例如全走左时,路径可以先向右走一段再向上,也可以一直向右走。为了得到一一对应,我们取规范折线:在所有能分开该方案的单调路径中,取最靠左上的一条,也就是取所有走右点的左上包络。这样得到的规范折线由方案唯一确定。反过来,任意一条规范折线也唯一确定一种合法选择:折线左上方机器人走左,右下方机器人走右,折线上的点走右。因此合法方案与规范折线一一对应。
规范折线经过的点按
因此,把所有去重后的二元组按
设排序后的
其中前面的
前面的
再把
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+10,mod=1e9+7;
int n,m,a[N],b[N],maxn=0;
ll dp[N];
pair<int,int> dot[N];
struct BIT{
ll tree[N];
inline int lowbit(int x){
return x&(-x);
}
inline void add(int x,ll k){
while(x<=maxn){
(tree[x]+=k)%=mod;
x+=lowbit(x);
}
}
inline ll query(int x){
ll res=0;
while(x){
(res+=tree[x])%=mod;
x-=lowbit(x);
}
return res;
}
}tree;
vector<int> x,y;
inline bool cmp(pair<int,int> x,pair<int,int> y){
if(x.first==y.first) return x.second>y.second;
return x.first<y.first;
}
signed main(){
cin.tie(0);cout.tie(0);
ios::sync_with_stdio(false);
freopen("esc.in","r",stdin);
freopen("esc.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=m;i++) cin>>b[i];
int cnt=0;
for(int i=1;i<=n;i++){
if(a[i]<b[1] || a[i]>b[m]) continue;
int pos=lower_bound(b+1,b+1+m,a[i])-b;
dot[++cnt]={a[i]-b[pos-1],b[pos]-a[i]};
x.push_back(dot[cnt].first);
y.push_back(dot[cnt].second);
}
sort(x.begin(),x.end());sort(y.begin(),y.end());
x.erase(unique(x.begin(),x.end()),x.end());
y.erase(unique(y.begin(),y.end()),y.end());
for(int i=1;i<=cnt;i++){
dot[i].first=lower_bound(x.begin(),x.end(),dot[i].first)-x.begin()+1;
dot[i].second=lower_bound(y.begin(),y.end(),dot[i].second)-y.begin()+1;
}
maxn=y.size();
sort(dot+1,dot+1+cnt,cmp);
cnt=unique(dot+1,dot+1+cnt)-dot-1;
ll ans=1;
for(int i=1;i<=cnt;i++){
ll add=tree.query(dot[i].second-1)+1;
(ans+=add)%=mod;
tree.add(dot[i].second,add);
}
cout<<ans;
return 0;
}