AT4353-[ARC101D]Robots and Exits【LIS】

正题

题目链接:https://www.luogu.com.cn/problem/AT4353


题目大意

数轴上有\(n\)个球\(m\)个洞,每次可以将所有球左移或者右移,球到洞的位置会掉下去。

求有多少让球掉进不同洞的方案。

\(1\leq n,m\leq 10^5\)


解题思路

设一个球距离左右洞的距离分别为\((x,y)\),那么一个球\((x_1,y_1)\)对球\((x_2,y_2)\)产生限制当且仅当\(x_1\leq x_2\)\(y_1\geq y_2\)

那么我们相当于找一些两两没有限制的数字的集合,一种方法是按照\(x\)升序排序,然后求\(y\)的上升序列数量即可。

时间复杂度\(O(n\log n)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define lowbit(x) (x&-x)
#define mp(x,y) make_pair(x,y)
using namespace std;
const ll N=1e5+10,P=1e9+7;
ll n,m,cnt,bnt,b[N],x[N],y[N],t[N],ans;
pair<ll ,ll >a[N];
void Change(ll x,ll val){
	while(x<=n){
		(t[x]+=val)%=P;
		x+=lowbit(x);
	}
	return;
}
ll Ask(ll x){
	ll ans=0;
	while(x){
		(ans+=t[x])%=P;
		x-=lowbit(x);
	}
	return ans;
}
signed main()
{
	freopen("hole.in","r",stdin);
	freopen("hole.out","w",stdout);
	scanf("%lld%lld",&n,&m);
	for(ll i=1;i<=n;i++)scanf("%lld",&x[i]);
	for(ll i=1;i<=m;i++)scanf("%lld",&y[i]);
	ll z=1;
	for(ll i=1;i<=n;i++){
		while(z<=m&&y[z]<x[i])z++;
		if(z==1||z>m||y[z]==x[i])continue;
		a[++cnt]=mp(x[i]-y[z-1],x[i]-y[z]);
		b[++bnt]=y[z]-x[i];
	}
	sort(a+1,a+1+cnt);
	b[++bnt]=0;sort(b+1,b+1+bnt);
	cnt=unique(a+1,a+1+cnt)-a-1;
	bnt=unique(b+1,b+1+bnt)-b-1;
	Change(1,1);ans=1;
	for(ll i=1;i<=cnt;i++){
		ll w=lower_bound(b+1,b+1+bnt,-a[i].second)-b;;
		ll sum=Ask(w-1);Change(w,sum);
		(ans+=sum)%=P;
	}
	printf("%lld\n",ans);
	return 0;
}
posted @ 2021-08-16 16:35  QuantAsk  阅读(27)  评论(0编辑  收藏  举报