AtCoder Regular Contest 101 F - Robots and Exits

在這裏插入圖片描述

題意

題意就是一個以爲數軸上某些位置有出口,某些位置有機器人。
然後你可以同時控制所以的機器人往左或往右走一格。
機器人走到出口就會立即退出。

求方案數。
一個不同的方案數當且僅當有某個機器人從不同出口出去。

思考歷程

這題我是某天晚上訓練快結束時看到的。
感覺很熟悉,因爲以前似乎也有個機器人的題。
然鵝想了很久的dp都感覺不太行。

其實模型稍微轉化一下模型就變成一個非常普及組的題目了。
當然這個轉化是真的奇妙。

題解

首先每個機器人其實都是獨立的,而這個機器人只有兩種情況對答案貢獻,往左往右。具體怎麼走都是可以的,當然左邊或右邊沒有出口的機器人就對答案沒有貢獻了。
然後我們這個模型就是:先構造出一個二維平面,每個機器人作爲一個點。把當前機器人距離左邊出口的距離作爲x軸座標,把距離右邊出口的距離作爲y軸座標。
這樣轉化完之後有什麼意義呢?

那麼向左向右的操作就相當於往下或往左。
這樣我們就可以畫出個神奇的分割線,分割線往左爲相當於左出口,分割線往下相當於右出口。
畫出來之後我們可以發現,不同的狀態就相當於這個分割線的左邊包含的機器人的不同。

那麼我們考慮一個dp[i]dp[i]表示當前第i個機器人放在左邊的方案,那麼這個dp顯然就是由當前點左下所有的dpdp值來轉移。
用樹狀數組維護即可。

代碼

#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]));
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章