題意
題意就是一個以爲數軸上某些位置有出口,某些位置有機器人。
然後你可以同時控制所以的機器人往左或往右走一格。
機器人走到出口就會立即退出。
求方案數。
一個不同的方案數當且僅當有某個機器人從不同出口出去。
思考歷程
這題我是某天晚上訓練快結束時看到的。
感覺很熟悉,因爲以前似乎也有個機器人的題。
然鵝想了很久的dp都感覺不太行。
其實模型稍微轉化一下模型就變成一個非常普及組的題目了。
當然這個轉化是真的奇妙。
題解
首先每個機器人其實都是獨立的,而這個機器人只有兩種情況對答案貢獻,往左往右。具體怎麼走都是可以的,當然左邊或右邊沒有出口的機器人就對答案沒有貢獻了。
然後我們這個模型就是:先構造出一個二維平面,每個機器人作爲一個點。把當前機器人距離左邊出口的距離作爲x軸座標,把距離右邊出口的距離作爲y軸座標。
這樣轉化完之後有什麼意義呢?
那麼向左向右的操作就相當於往下或往左。
這樣我們就可以畫出個神奇的分割線,分割線往左爲相當於左出口,分割線往下相當於右出口。
畫出來之後我們可以發現,不同的狀態就相當於這個分割線的左邊包含的機器人的不同。
那麼我們考慮一個表示當前第i個機器人放在左邊的方案,那麼這個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]));
}