题目链接
题意:这是一个一维推箱子的游戏,你站在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());
}
}