1D Sokoban

\(1D Sokoban\)

在数轴上有n个箱子,有n个关键点,给出箱子和关键点的坐标,你现在站在0的位置,可以任意移动推箱子,求解最后能够使得多少箱子在关键点上,注意人不能越过箱子。

那么我们发现你最后推到的位置一定是一个关键点,然后箱子会覆盖一个区间的关键点,那么我们可以利用队列维护关键点集合,然后统计区间长度即可。

#include<bits/stdc++.h>
#define LL long long
#define V inline void
#define I inline int
#define FOR(i,a,b) for(register int i=a,end##i=b;i<=end##i;++i)
#define REP(i,a,b) for(register int i=a,end##i=b;i>=end##i;--i)
#define go(i,x) for(int i=hed[x];i;i=e[i].pre)
using namespace std;
inline int read()
{
	char x='\0';
	int fh=1,sum=0;
	for(x=getchar();x<'0'||x>'9';x=getchar())if(x=='-')fh=-1;
	for(;x>='0'&&x<='9';x=getchar())sum=sum*10+x-'0';
	return fh*sum;
}
const int N=4e5+9;
int T,n,m;
struct node{
	int pos,tp,val;
}a[N],b[N];
int acnt,bcnt;
inline bool cmp1(node x,node y)
{
	if(x.pos!=y.pos)return x.pos>y.pos;
	return x.tp<y.tp;
}
inline bool cmp2(node x,node y)
{
	if(x.pos!=y.pos)return x.pos<y.pos;
	return x.tp<y.tp;
}
map<int,int>mp;
int main()
{
	T=read();
	while(T--)
	{
		mp.clear();
		acnt=0,bcnt=0;
		n=read(),m=read();
		FOR(i,1,n)
		{
			int x=read();
			if(x<0)a[++acnt]={x,0},mp[x]=acnt;
			else b[++bcnt]={x,0},mp[x]=bcnt;
		}
		int sva=0,svb=0;
		FOR(i,1,m)
		{
			int x=read();
			if(x<0)
			{
				a[++acnt]={x,1};
				if(mp.find(x)!=mp.end())
					a[mp[x]].val=1,sva++;
			}
			else
			{
				b[++bcnt]={x,1};
				if(mp.find(x)!=mp.end())
					b[mp[x]].val=1,svb++;
			}
		}
		sort(a+1,a+acnt+1,cmp1);
		sort(b+1,b+bcnt+1,cmp2);
		int ansa=sva,ansb=svb;
		int len=0;
		queue<int>q;
		FOR(i,1,acnt)
		{
			if(a[i].tp==0)len++,sva-=a[i].val;
			else
			{
				q.push(a[i].pos);
				while(q.size()&&q.front()>=a[i].pos+len)q.pop();
				ansa=max(ansa,sva+(int)q.size());
			}
		}
		len=0;
		while(!q.empty())q.pop();
		FOR(i,1,bcnt)
		{
			if(b[i].tp==0)len++,svb-=b[i].val;
			else
			{
				q.push(b[i].pos);
				while(q.size()&&q.front()<=b[i].pos-len)q.pop();
				ansb=max(ansb,svb+(int)q.size());
			}
		}
		printf("%d\n",ansa+ansb);
	}
	return 0;
}

 
posted @ 2021-03-09 20:49  dinlon  阅读(91)  评论(0)    收藏  举报