单调队列+二分 G

B. Queue

这个题目会做的很偶然,突然想到的,因为我们要求离这只海象的最远的比他年轻的海象,这个年轻的海象可以用单调栈维护。

就是从前往后遍历一遍,单调栈里面存年龄从小往大的海象,这个为什么这么存呢,因为如果后面有比这个队列里面更年轻的海象,

那么就可以更新,而且这个更新是正确的,不会有影响,这个可以自己想一想/

然后就可以得到一个单调栈的数组,这个时候因为单调栈是单调的,所以可以用二分来查找我们所需要的值。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <map>
#include <iostream>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
typedef long long ll;
int queue_min[maxn];
int f1 = 1, t1 = 1, r = 1;
int ans[maxn];
ll num[maxn];
ll a[maxn];

int ok(ll s)
{
    int x = 1, y = t1;
    int mid = (x + y) / 2;
    while(x<=y)
    {
        mid = (x + y) / 2;
        if (a[queue_min[mid]] >= s) y = mid-1;
        else x = mid + 1;
        //printf("x=%d y=%d mid=%d
",x,y, mid);
    }
    //printf("mid=%d queue_min=%d
", mid, queue_min[mid]);
    if (a[queue_min[mid]] >= s) return queue_min[mid - 1];
    return queue_min[mid];
}

int main()
{
    int n;
    scanf("%d", &n);
    f1 = 1, t1 = 1, r = 1;
    for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
    queue_min[1] = 1;
    while(r<n)
    {
        r++;
        while (f1 <= t1 && a[r] < a[queue_min[t1]]) t1--;
        queue_min[++t1] = r;
    }
    for (int i = f1; i <= t1; i++) {
        num[i] = a[queue_min[i]];
        // printf("queue_min[%d]=%d
", i, queue_min[i]);
        // printf("num[%d]=%lld
", i, num[i]);
    }
    for(int i=1;i<=n;i++)
    {
        int f = ok(a[i]);
        //printf("F=%d
",f);
        if (f < i) ans[i] = -1;
        else ans[i] = f - i - 1;
        printf("%d ", ans[i]);
    }
    printf("
");
    return 0;
}
单调栈 海象

小阳买水果

这个题目和上面那个其实是一样的,但是我居然没有发现,这个要先前缀和处理一下,然后你就发现其实求的就是 比如 i ,求的就是 i 后面的比 i 更大的sum的最远位置。

也是二分+单调队列

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <iostream>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn = 2e6 + 10;
typedef long long ll;
int queue_max[maxn];
int a[maxn], num[maxn];
ll sum[maxn];
int f1, t1;
int r;

int ok(ll s) {
    int x = 1, y = t1;
    int mid = (x + y) / 2;
    while (x <= y) {
        mid = (x + y) / 2;
        if (sum[queue_max[mid]] > s) x = mid + 1;
        else y = mid - 1;
        //printf("x=%d y=%d mid=%d
", x, y, mid);
    }
    //printf("mid=%d queue_min=%d
", mid, queue_min[mid]);
    if (sum[queue_max[mid]] <= s) return queue_max[mid - 1];
    return queue_max[mid];
}

int main() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%lld", &sum[i]);
        sum[i] += sum[i - 1];
    //    printf("sum[%d]=%lld
", i, sum[i]);
    }
    f1 = 1, t1 = 1;
    r = 2;
    queue_max[1] = 1;
    int ans = 0;
    while (r <= n) {
        while (t1 >= f1 && sum[r] > sum[queue_max[t1]]) t1--;
        queue_max[++t1] = r;
        //printf("queue_max[%d]=%d
", t1, queue_max[t1]);
        r++;
    }
    for (int i = f1; i <= t1; i++) {
        num[i] = sum[queue_max[i]];
        //printf("queue[%d]=%d
", i, queue_max[i]);
    }
    for (int i = 1; i <= n; i++) {
        int f = ok(sum[i]);
        //printf("i=%d f=%d
", i, f);
        if (f > i)
        {
            if (sum[i] >= 0) ans = max(ans, f - i + 1);
            else ans = max(ans, f - i);
        }
    }
    printf("%d
", ans);
    return 0;
}
二分+单调队列
原文地址:https://www.cnblogs.com/EchoZQN/p/11195563.html