题目传送门
这道题利用了C++ STL库里面的upper_bound模板(当然也可以手搓)当然也可以使用lower_bound模板,具体的使用请参考大佬博客:
大佬博客传送门
那么这道题关于暴力这件事。。就是分正负两边操作,将a[i]和b[i]重合的地方总和记为初始的答案res,现在把你目前移动的箱子当成一辆火车,每经过一个a[i],我们的火车就多了一节,枚举火车头是所有我们询问的地方,然后求出答案最大的情况。
#include<iostream>
#include<map>
#include<algorithm>
using namespace std;
map<int,int>mp;
int input[2102102];
int inask[2102102];
int a[2102102];
int b[2102102];
int solve(int lena,int lenb){
int count=0;
mp.clear();
for(int i=1;i<=lena;i++) mp[a[i]]=1;
for(int i=1;i<=lenb;i++) if(mp[b[i]])count++;
int res=count;
int ans=res;
for(int i=1;i<=lenb;i++){
if(mp[b[i]]){
res--;
continue;
}
//为什么continue,那是因为这个位置已经有了,前面的位置是前面求得的最大值,(挪到这里来,所有ab重合的位置一定会小于等于上一回合算出来的ans因此这一局一定要跳过)。
int pp=upper_bound(a+1,a+1+lena,b[i])-a-1;
//upper_bound:返回大于这个数的第一个数的迭代器,
//那么这句话的意思就是
//把目前正在推的所有箱子的第一个挪到b[i]
//剩下的目前推的箱子就怼在一起了
//也就是看b[i]这前面(包括b[i]这个位置)一共有pp个箱子
int qq=upper_bound(b+1,b+1+lenb,b[i]-pp)-b;
//这个意思就是我们的正在推的箱子的头部的位置在
//b[i]这个位置,尾部的位置在b[i]-pp+1这个位置
//因此这个位置用lower_bound(b+1,b+1+lenb,b[i]-pp+1)-b;
//也是可以滴!
ans=max(ans,res+i-qq+1);
//这里把res看成一部分这是我们枚举的这个位置之后的所有和
//a[i]重合的地方的总和,剩下的i-qq+1后面来解释
//为什么要加1呢,那就是qq是我们刚好有箱子的第一个位置
//那么前面那个位置是刚好没有的
//所以我们要+1代表的是多减掉了一个箱子的位置
//咱们还要把它加回来
}
return ans;
}
int main(){
int T;
cin>>T;
while(T--){
int n,m;
int lena=0,lenb=0;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>input[i];
if(input[i]>=0) a[++lena]=input[i];
}
for(int i=1;i<=m;i++){
cin>>inask[i];
if(inask[i]>=0) b[++lenb]=inask[i];
}
int ans=solve(lena,lenb);
lena=lenb=0;
for(int i=n;i>=1;i--){
if(input[i]<0) a[++lena]=-input[i];
}
for(int i=m;i>=1;i--){
if(inask[i]<0) b[++lenb]=-inask[i];
}
ans+=solve(lena,lenb);
cout<<ans<<endl;
}
return 0;
}