C. 1D Sokoban 二分,思维
作者:互联网
转:
C. 1D Sokoban 二分,思维
C. 1D Sokoban 二分,思维
题目大意:
这是一个一维推箱子的游戏,你站在0这个位置,然后在这个轴上有n个箱子,保证没有箱子在0这个位置,然后有 m 个特殊的位置,你每次推箱子都是推动一个单位,如果你把箱子推向的下一个单位上有箱子,那么那个箱子也会往后挪动一个单位,问:经过你的努力,你最多可以让多少个箱子在特殊位置上。
T 组输入,保证 n 之和不会超过 (2*10^5) ,保证 m 之和不会超过 (2*10^5) ,给你两个序列都是按照单调递增的方式给定。
题解:
- 首先明确你在0这个位置,那么你只能推左边的第一个箱子,或者右边的第一个箱子
- 如果你一直往左边推,那么可能会有连续的一些箱子,然后之后的箱子还是保持原样
- 枚举你往左推能推到的那个特殊点,然后可以直接判断出每一个位置的最大值
写起来还是挺麻烦的,注意细节!
#include
using namespace std;
typedef long long ll;
const int maxn = 4e5+10;
int a[maxn],b[maxn];
int A[maxn],B[maxn],ta,tb,last[maxn];
int solve(){
if(!ta||!tb) return 0;
int now = ta;
last[tb + 1] = 0;
for(int i=tb;i>=1;i--) {
last[i] = last[i+1];
while(now>=1&&B[i]<a[now]) now--;="" if(now="">=1&&B[i]==A[now]) last[i]++,now--;
// printf("i = %d now = %d b = %d last[%d]=%dn",i,now,B[i],i,last[i]);
}
int pre = 1,ans = 0;
for(int i=1;i<=tb;i++){
if(B[i]<a[1]) continue;="" while(pre+1<="ta&&A[pre+1]<=B[i]+pre)" pre++;="" int="" x="upper_bound(B+1,B+1+tb,B[i]" +="" pre="" -="" 1)="" b="" 1;="" ans="max(ans,x" i="" 1="" last[x="" 1]);="" printf("i="%d" b[%d]="%d" %dn",i,i,b[i],x,ans,pre,last[x+1]);="" }="" return="" ans;="" main()="" {="" t;="" scanf("%d",="" &t);="" while="" (t--)="" n,="" m;="" scanf("%d%d",="" &n,="" &m);="" for="" (int="" <="n;" i++)="" &a[i]);="" &b[i]);="" ta="0,tb" =="" 0;="" for(int="" if(a[i]="">=0) A[++ta] = a[i];
}
for(int i=1;i<=m;i++){
if(b[i]>=0) B[++tb] = b[i];
}
// printf("ta = %d tb = %dn",ta,tb);
int ans = solve();
ta = tb = 0;
// printf("ans = %dn",ans);
for(int i=n;i>=1;i--){
if(a[i]<0) A[++ta] = -a[i];
}
for(int i=m;i>=1;i--){
if(b[i]<0) B[++tb] = -b[i];
}
ans += solve();
printf("%dn",ans);
}
return 0;
}
标签:二分,箱子,last,int,1D,Sokoban,now,tb,ta 来源: https://www.cnblogs.com/wangtcc/p/14613023.html