题意
题意就是一个以为数轴上某些位置有出口,某些位置有机器人。
然后你可以同时控制所以的机器人往左或往右走一格。
机器人走到出口就会立即退出。
求方案数。
一个不同的方案数当且仅当有某个机器人从不同出口出去。
思考历程
这题我是某天晚上训练快结束时看到的。
感觉很熟悉,因为以前似乎也有个机器人的题。
然鹅想了很久的dp都感觉不太行。
其实模型稍微转化一下模型就变成一个非常普及组的题目了。
当然这个转化是真的奇妙。
题解
首先每个机器人其实都是独立的,而这个机器人只有两种情况对答案贡献,往左往右。具体怎么走都是可以的,当然左边或右边没有出口的机器人就对答案没有贡献了。
然后我们这个模型就是:先构造出一个二维平面,每个机器人作为一个点。把当前机器人距离左边出口的距离作为x轴坐标,把距离右边出口的距离作为y轴坐标。
这样转化完之后有什么意义呢?
那么向左向右的操作就相当于往下或往左。
这样我们就可以画出个神奇的分割线,分割线往左为相当于左出口,分割线往下相当于右出口。
画出来之后我们可以发现,不同的状态就相当于这个分割线的左边包含的机器人的不同。
那么我们考虑一个
d
p
[
i
]
dp[i]
dp[i]表示当前第i个机器人放在左边的方案,那么这个dp显然就是由当前点左下所有的
d
p
dp
dp值来转移。
用树状数组维护即可。
代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
const long long mo=1000000007;
const int maxn=200010;
int n,m,gs,x[maxn],y[maxn];
long long c[maxn*10],sum[maxn],xx[maxn*10],yy[maxn*10],op[maxn*10],id[maxn*10];
void qsort2(int l,int r)
{
int i=l;int j=r;
int m=yy[(i+j)/2];
int m1=xx[(i+j)/2];
while (i<=j)
{
while ((yy[i]<m) || (yy[i]==m && xx[i]<m1)) i++;
while ((yy[j]>m) || (yy[j]==m && xx[j]>m1)) j--;
if (i<=j)
{
swap(yy[i],yy[j]);
swap(xx[i],xx[j]);
i++;j--;
}
}
if (l<j) qsort2(l,j);
if (r>i) qsort2(i,r);
}
void qsort(int l,int r)
{
int i=l;int j=r;
int m=yy[(i+j)/2];
int m1=xx[(i+j)/2];
while (i<=j)
{
while ((yy[i]<m) || (yy[i]==m && xx[i]<m1)) i++;
while ((yy[j]>m) || (yy[j]==m && xx[j]>m1)) j--;
if (i<=j)
{
swap(yy[i],yy[j]);
swap(xx[i],xx[j]);
i++;j--;
}
}
if (l<j) qsort(l,j);
if (r>i) qsort(i,r);
}
void qsort1(int l,int r)
{
int i=l;int j=r;
int m=op[(i+j)/2];
while (i<=j)
{
while (op[i]<m) i++;
while (op[j]>m) j--;
if (i<=j)
{
swap(op[i],op[j]);
swap(id[i],id[j]);
i++;j--;
}
}
if (l<j) qsort1(l,j);
if (r>i) qsort1(i,r);
}
int lowbit(int x)
{
return x&(-x);
}
void modify(int i,long long k)
{
while (i<=gs)
{
c[i]=(c[i]+k)%mo;
i+=lowbit(i);
}
}
long long getans(int i)
{
long long gg=0;
int kk=0;
while (i>0)
{
gg=(gg+c[i])%mo;
kk=lowbit(i);
i-=kk;
}
return gg;
}
int main()
{
// freopen("data.in","r",stdin);
scanf("%d%d",&n,&m);
int zd=0;
for (int i=1;i<=n;i++)
{
scanf("%d",&x[i]);
zd=max(zd,x[i]);
}
for (int i=1;i<=m;i++)
{
scanf("%d",&y[i]);
zd=max(zd,y[i]);
}
int l=1;
gs=2;
xx[1]=1;yy[1]=1;
xx[2]=zd+1;yy[2]=zd+1;
for (int i=1;i<=n;i++)
{
while (x[i]>y[l] && l<=m) l++;
if (l>m) break;
if (l>1 && x[i]>y[l-1] && x[i]<y[l])
{
gs++;
xx[gs]=x[i]-y[l-1]+1;
yy[gs]=y[l]-x[i]+1;
}
}
qsort(1,gs);
for (int i=1;i<=gs;i++)
{
op[i]=xx[i];
id[i]=i;
}
qsort1(1,gs);
int js=0;
for (int i=1;i<=gs;i++)
{
if (op[i]!=op[i-1]) js++;
xx[id[i]]=js;
}
modify(1,1);
l=2;
int r=2;
int jss=0;
for (int i=2;i<=gs;i++)
{
if (xx[i]==xx[i-1] && yy[i]==yy[i-1])
{
xx[i-1]=2000000000;
yy[i-1]=2000000000;
jss++;
}
}
qsort2(1,gs);
gs-=jss;
while (l<gs)
{
while (yy[l]==yy[l+1])
{
sum[l]=getans(xx[l]-1);
l++;
}
if (yy[l]!=yy[l+1])
{
sum[l]=getans(xx[l]-1);
l++;
}
while (r<l)
{
modify(xx[r],sum[r]);
r++;
}
}
printf("%lld\n",getans(xx[gs]));
}