5289 Assignment (RMQ+二分区间)

题目链接:5289 Assignment

题意:给出n和K,表示有一串n个数的序列,存在多少个区间,该区间中任意两个数的差小于k

思路:

1.区间任意两个数的小于K 等价于 区间max-min<k,用RMQ来维护,区间最大最小值

2.最后暴力枚举区间必定要超时,发现随着区间的扩大max-min的值也在变大(非递减),有单调性就容易想到二分,所以是枚举左端点,二分找右端点。

AC代码:

#include<stdio.h>
#include <algorithm>
using namespace std;
#define LL int
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const LL MAXN = 100010;
LL dp[3][MAXN][20];
LL mm[MAXN],a[MAXN];
//初始化RMQ, b数组下标从1开始,从0开始简单修改
void initRMQ(LL n,LL b[]) {
    mm[0] = -1;
    for(LL i = 1; i <= n; i++) {
        mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
        dp[0][i][0] = dp[1][i][0]=b[i];
    }
    for(LL j = 1; j <= mm[n]; j++) {
        for(LL i = 1; i + (1<<j) -1 <= n; i++) {
            dp[0][i][j] = max(dp[0][i][j-1],dp[0][i+(1<<(j-1))][j-1]);
            dp[1][i][j] = min(dp[1][i][j-1],dp[1][i+(1<<(j-1))][j-1]);
        }
    }
}
//查询最大值
LL rmq(LL x,LL y) {
    LL k = mm[y-x+1];
    LL tmp=max(dp[0][x][k],dp[0][y-(1<<k)+1][k]);
    tmp-=min(dp[1][x][k],dp[1][y-(1<<k)+1][k]);
    return tmp;
}

int main() {
    LL t,i,n;
    LL k;
    scanf("%d",&t);
    while(t--) {
        scanf("%d %d",&n,&k);
        for(i=1; i<=n; i++)
            scanf("%d",&a[i]);
        initRMQ(n,a);
        LL l,r,m;
        __int64 ans=0;
        for(i=1; i<=n; i++) {
            l=i,r=n;
            LL t1,t2,tmp;
            while(l<=r) {
                m=(l+r)/2;
                tmp=rmq(i,m);
                if(tmp<k)  l=m+1;
                else r=m-1;
            }
            //printf(".....[l %d m%d r%d],tmp=%d\n",l,m,r,tmp);
            ans+=(__int64)(l-i);
        }
        printf("%I64d\n",ans);
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-05 13:52:41

5289 Assignment (RMQ+二分区间)的相关文章

HDU - 5289 Assignment (RMQ+二分)

题目链接: Assignment  题意: 给出一个数列,问其中存在多少连续子序列,使得子序列的最大值-最小值<k. 题解: RMQ先处理出每个区间的最大值和最小值(复杂度为:n×logn),相当于求出了每个区间的最大值-最小值.那么现在我们枚举左端点,二分右端点就可以在n×logn×logn的时间内过. 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAX_N = 1e5+9; 4 int vec[MAX_N]

HDU 5289 Assignment(二分+RMQ-ST)

Assignment Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 3813    Accepted Submission(s): 1771 Problem Description Tom owns a company and he is the boss. There are n staffs which are numbered

hdu 5289 Assignment 二分+rmq

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5289 Assignment Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 332    Accepted Submission(s): 169 Problem Description Tom owns a company and he is

hdu 5289 Assignment(2015多校第一场第2题)RMQ+二分(或者multiset模拟过程)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5289 题意:给你n个数和k,求有多少的区间使得区间内部任意两个数的差值小于k,输出符合要求的区间个数 思路:求出区间的最大最小值,只要他们的差值小于k,那么这个区间就符合要求,但是由于n较大,用暴力一定超时,所以就要用别的方法了:而RMQ是可以求区间的最值的,而且预处理的复杂度只有O(nlogn),而查询只是O(1)处理,这样相对来说节约了时间,再根据右端点来二分枚举左端点(其实不用二分好像更快,估

HDU 5289 Assignment(2015 多校第一场二分 + RMQ)

Assignment Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 627    Accepted Submission(s): 318 Problem Description Tom owns a company and he is the boss. There are n staffs which are numbered fr

HDU 5089 Assignment(rmq+二分 或 单调队列)

Assignment Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 557    Accepted Submission(s): 280 Problem Description Tom owns a company and he is the boss. There are n staffs which are numbered fr

poj 2452(RMQ+二分查找)

题目链接: http://poj.org/problem?id=2452 题意:在区间[1,n]上找到满足 a[i]<a[k]<a[j] (i<=k<=j) 的最大子区间 (j-i)如不存在输出 -1. 思路:枚举i,找到 i右边第一个不大于(不是小于) a[i]的数a[k](二分查找+RMQ某段区间的最小值是否小于a[i].最后确定到一个点),于是我们可以得到在区间[i,k-1]范围内的数都会大于 a[i] ,所以对于下标i,它对应的最长区间必定在[i,k-1]之间. 所以,我们

HDU 5875 st+二分区间

题目大意:给你n个数,q次询问,每次询问区间[l, r],问a[i]%a[i + 1] % a[i + 2]...%a[j](j <= r)的值 思路:st预处理维护,在二分区间,复杂度n*(logn)*logn //看看会不会爆int!数组会不会少了一维! //取物问题一定要小心先手胜利的条件 #include <bits/stdc++.h> using namespace std; #define LL long long #define ALL(a) a.begin(), a.en

CodeForces 52C Circular RMQ(区间循环线段树,区间更新,区间求和)

转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://codeforces.com/problemset/problem/52/C You are given circular array a0,?a1,?...,?an?-?1. There are two types of operations with it: inc(lf,?rg,?v) - this operation increases each element on the segm