AtCoder Regular Contest 101 F - Robots and Exits

在这里插入图片描述

题意

题意就是一个以为数轴上某些位置有出口,某些位置有机器人。
然后你可以同时控制所以的机器人往左或往右走一格。
机器人走到出口就会立即退出。

求方案数。
一个不同的方案数当且仅当有某个机器人从不同出口出去。

思考历程

这题我是某天晚上训练快结束时看到的。
感觉很熟悉,因为以前似乎也有个机器人的题。
然鹅想了很久的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]));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值