zoukankan      html  css  js  c++  java
  • C. 1D Sokoban 二分,思维

    C. 1D Sokoban 二分,思维

    题目大意:

    这是一个一维推箱子的游戏,你站在0这个位置,然后在这个轴上有n个箱子,保证没有箱子在0这个位置,然后有 m 个特殊的位置,你每次推箱子都是推动一个单位,如果你把箱子推向的下一个单位上有箱子,那么那个箱子也会往后挪动一个单位,问:经过你的努力,你最多可以让多少个箱子在特殊位置上。

    T 组输入,保证 n 之和不会超过 (2*10^5) ,保证 m 之和不会超过 (2*10^5) ,给你两个序列都是按照单调递增的方式给定。

    题解:

    • 首先明确你在0这个位置,那么你只能推左边的第一个箱子,或者右边的第一个箱子
    • 如果你一直往左边推,那么可能会有连续的一些箱子,然后之后的箱子还是保持原样
    • 枚举你往左推能推到的那个特殊点,然后可以直接判断出每一个位置的最大值

    写起来还是挺麻烦的,注意细节!

    #include <bits/stdc++.h>
    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]=%d
    ",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 x = %d ans = %d pre = %d %d
    ",i,i,B[i],x,ans,pre,last[x+1]);
        }
        return ans;
    }
    int main() {
        int T;
        scanf("%d", &T);
        while (T--) {
            int n, m;
            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]);
            ta = 0,tb = 0;
            for(int i=1;i<=n;i++){
                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 = %d
    ",ta,tb);
            int ans = solve();
            ta = tb = 0;
    //        printf("ans = %d
    ",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("%d
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    Delphi使用Indy、ICS组件读取网页
    用SendNotifyMessage代替PostMessage避免消息丢失
    LuaPlus的编译和引用
    如何转换和输出超大整数(64位)
    jQuery 源码:封装 Event
    jQuery 源码:操作样式
    jQuery 源码:元素位置
    模拟ES5 Array.prototype.reduce
    as 和 is 运算符以及安全的类型强制转换
    计算机编程基础
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/14476628.html
Copyright © 2011-2022 走看看