​题目链接​题目大意: 推箱子游戏:你站在0点,有n个箱子,他们分别在codeforces 1499C 1D Sokoban(二分+思维)_#define上,保证0点没箱子,还有m个好位子,你只能向左或向右推箱子,如遇其他箱子,就相当于你推着“连体婴儿”,推两个箱子。问你最多可以箱子在好的位置。


思路:

  • 首先我们知道我们在0点,而且只能向左或者向右推第一个箱子。
  • 其次是我们推箱子的时候可能会出现个一些连续的箱子,后面的则不动,还在原来的位置。
  • 最后我们可以枚举我们当前推到的特殊点也就是好的位置。判断最大值就行了。
    复杂度的话,移动1e5个点,其次二分查找log(n)的,所以是nlog(n)的复杂度。
    我们需要维护一个后面本来就在好位置的,所以需要维护一个后缀和。在推到特殊位置时我要知道我们推了几个箱子,而且要知道推得这么多箱子,最多有多少在指定的好位置上,以为我们推多箱子时是连续的所以我们只需要知道右端点,左端点就是我们枚举的指定位置。
#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
typedef pair<ll,ll> pii;
#define
#define
#define
#define
#define
#define
const int maxn=2e5+10;
#define
#define
#define
const int mod=1e9+7;
const int MOD=1e9+7;

inline int read() {
int x=0;
bool t=false;
char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}

ll gcd(ll a,ll b) {
while(b) {
ll tmp=a%b;
a=b;
b=tmp;
}
return a;
}
ll exgcd(ll a,ll b,ll &x,ll &y) { //扩欧
if(b==0) {
x=1,y=0;
return a;
}
ll d=exgcd(b,a%b,y,x);
y=y-a/b*x;
return d;
}
ll n,m;
ll a[maxn],b[maxn],d[maxn],c[maxn];
ll cnta, cntb;
ll dis[maxn];
ll sovle(){
if(!cnta||!cntb) return 0;
ll now=cnta;
dis[cntb+1]=0;
for(int i=cntb;i>=1;i--){///维护一个本身就好的后缀
dis[i]=dis[i+1];///从前一个状态转移过来
while(now>=1&&d[i]<c[now]) now--;///找到一个小于等于d[i]的位置
if(now>=1&&d[i]==c[now]) dis[i]++,now--;///原位是好的
}
ll p=1,ans=0;
for(int i=1;i<=cntb;i++){
if(d[i]<c[1]) continue;///这个位置比第一个箱子还小没办法推到
while(p+1<=cnta&&c[p+1]<=d[i]+p) p++;///连体婴儿 p个箱子
ll x=upper_bound(d+1,d+1+cntb,d[i]+p-1)-d-1;///找到后一个就是将其个连体婴儿的第一个推到i位//置,
ans=max(ans,x+1-i+dis[x+1]);///连体婴儿的数量加上本身就是好的数量求个最大值。
}
return ans;
}
int main() {
ll t;
cin>>t;
while(t--) {
scanf("%lld%lld",&n,&m);
cnta=cntb=0;
ll ans=0;
for(int i=1; i<=n; i++) {
scanf("%lld",&a[i]);
if(a[i]>=0)
c[++cnta]=a[i];
}
for(int i=1; i<=m; i++) {
scanf("%lld",&b[i]);
if(b[i]>=0)
d[++cntb]=b[i];
}
ans=sovle();///大于0的数量
cnta=cntb=0;
for(int i=n;i>=1;i--){
if(a[i]<0)c[++cnta]=-a[i];
}
for(int i=m;i>=1;i--){
if(b[i]<0)d[++cntb]=-b[i];
}
ans+=sovle();///小于0的数量
printf("%lld\n",ans);
}

return 0;
}