arc101F - Robots and Exits

题目大意

题解

一开始想枚举每段的分界再判断,然而不好搞

实际上把每个点到两边的距离设为(x,y),类似https://www.cnblogs.com/gmh77/p/12813589.html,变为用一条折线把所有点分成两个集合

直接dp折线,转移时要么继承上一行位置,要么转移到前面的某个点,线段树维护

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define add(a,b) a=((a)+(b))%1000000007
#define mod 1000000007
#define N 1000000000
#define ll long long
//#define file
using namespace std;

struct type{int x,tp;} a[200001];
struct Type{int x,y;} b[200001];
int tr[7000001][2],X[200001],Y[200001],tot,n,m,i,j,k,l,len;
ll Tr[7000001],ans,s;

bool cmp(type a,type b) {return a.x<b.x;}
bool Cmp(Type a,Type b) {return a.x<b.x || a.x==b.x && a.y>b.y;}

void New(int t,int x) {if (!tr[t][x]) tr[t][x]=++len;}
void change(int t,int l,int r,int x,ll s)
{
	int mid=(l+r)/2;
	add(Tr[t],s);
	if (l==r) return;
	
	if (x<=mid) New(t,0),change(tr[t][0],l,mid,x,s);
	else New(t,1),change(tr[t][1],mid+1,r,x,s);
}
ll find(int t,int l,int r,int x,int y)
{
	int mid=(l+r)/2;
	ll ans=0;
	if (x<=l && r<=y) return Tr[t];
	
	if (x<=mid && tr[t][0]) add(ans,find(tr[t][0],l,mid,x,y));
	if (mid<y && tr[t][1]) add(ans,find(tr[t][1],mid+1,r,x,y));
	return ans;
}

int main()
{
	#ifdef file
	freopen("arc101f.in","r",stdin);
	#endif
	
	scanf("%d%d",&n,&m);
	fo(i,1,n) scanf("%d",&j),a[++tot]={j,0};
	fo(i,1,m) scanf("%d",&j),a[++tot]={j,1};
	
	sort(a+1,a+tot+1,cmp);
	l=0;
	fo(i,1,tot)
	if (a[i].tp)
	l=a[i].x; else X[i]=l?(a[i].x-l):0;
	l=0;
	fd(i,tot,1)
	if (a[i].tp)
	l=a[i].x; else Y[i]=l?(l-a[i].x):0;
	
	l=0;
	fo(i,1,tot) if (X[i] && Y[i]) b[++l]={X[i],Y[i]};
	tot=l;
	sort(b+1,b+tot+1,Cmp);
	l=0;
	fo(i,1,tot) if (b[i].x!=b[i-1].x || b[i].y!=b[i-1].y) b[++l]=b[i];
	tot=l;
	
	len=1;
	change(1,1,N,N,1);
	fd(i,tot,1)
	{
		s=find(1,1,N,b[i].y,N);
		if (b[i].y==1) add(ans,s);
		else change(1,1,N,b[i].y-1,s);
	}
	add(ans,Tr[1]);
	printf("%lld\n",ans);
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}
posted @ 2020-09-09 21:35  gmh77  阅读(184)  评论(0编辑  收藏  举报