cf1494 C. 1D Sokoban(二分+模拟)

Posted 为什么他们cf写的这么快

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cf1494 C. 1D Sokoban(二分+模拟)相关的知识,希望对你有一定的参考价值。

题目链接
在这里插入图片描述
在这里插入图片描述
题意:这是一个一维推箱子的游戏,你站在0这个位置,然后在这个轴上有n个箱子,保证没有箱子在0这个位置,然后有 m 个特殊的位置,你每次推箱子都是推动一个单位,如果你把箱子推向的下一个单位上有箱子,那么那个箱子也会往后挪动一个单位,问:经过你的努力,你最多可以让多少个箱子在特殊位置上。
思路:能推的肯定只有两边的第一个位置,设为位置p,我们每次判断一下把a【p】移到b【i】里那个收益最大就可以了。模拟题嘛,最难的还是代码的实现,注释里都有,最好能自己实现一遍,毕竟一个+1,-1这种边界控制也着实头疼。

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int n,m,T,a[maxn],b[maxn],pre[maxn];
int query1()//向右推 
{
	int res=0,p=0,now;
	for(int i=1;i<=n;++i) if(a[i]>=0){now=p=i;break;}//p是右边第一个箱子位置 
	if(p==0) return 0;
	for(int i=1;i<=m;++i)
	if(b[i]>=a[p]){
		while(now+1<=n&&a[now+1]<=b[i]+now-p+1) ++now;//这里的now-p的意思是对于a【p】这个位置向右推到b【i】的过程中能有now-p块箱子能合并到一起 
		int temp=upper_bound(b+1,b+1+m,b[i]+now-p)-b-i;//再判断这一块合并的箱子能有几个弄到特殊位置 
		res=max(res,temp+pre[n]-pre[now]);//这里别忘了算上后面pre,因为你后面可能本来就有个人箱子本身就在特殊位置了 
	}
	return res;
}
int query2()//向左推,与query1类似 
{
	int res=0,p=0,now;
	for(int i=n;i>=1;--i) if(a[i]<=0){now=p=i;break;}
	if(p==0) return 0;
	for(int i=m;i>=1;--i)
	if(b[i]<=a[p]){
		while(now-1>=1&&a[now-1]>=b[i]-p+now-1) --now;
		int temp=i-(lower_bound(b+1,b+1+m,b[i]-p+now)-b)+1;
		res=max(res,temp+pre[now-1]);
	}
	return res;
}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;++i) scanf("%d",&a[i]);
		for(int i=1;i<=m;++i) scanf("%d",&b[i]);
		for(int i=1;i<=n;++i)//pre数组代码在【1,i】中有多少个箱子本身就在特殊位置了 
		{
			pre[i]=0;
			int pos=lower_bound(b+1,b+1+m,a[i])-b;
			if(pos>=1&&pos<=m&&a[i]==b[pos]) ++pre[i];
			pre[i]+=pre[i-1];
		}
		int ans=query1();
		printf("%d\\n",ans+query2());
	}
}

以上是关于cf1494 C. 1D Sokoban(二分+模拟)的主要内容,如果未能解决你的问题,请参考以下文章

CF w1d1 C. The Party and Sweets

CF#537 C. Creative Snap /// DFS

C. Binary Search

CF w1d2 A. Superhero Transformation

cf C. Eugene and an array

C. Ayoub and Lost Array cf dp