一开始想枚举每段的分界再判断,然而不好搞
实际上把每个点到两边的距离设为(x,y),类似https://www.cnblogs.com/gmh77/p/12813589.html,变为用一条折线把所有点分成两个集合
直接dp折线,转移时要么继承上一行位置,要么转移到前面的某个点,线段树维护
#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;
}
原文:https://www.cnblogs.com/gmh77/p/13642164.html