多校第一场 hdu 5289 Assignment(rmq+二分)

来源:互联网 发布:网络作家的生活 编辑:程序博客网 时间:2024/05/17 01:43

题目链接:

点击打开链接

题目大意:

给出一个序列,问能找出多少个连续区间,区间内最大最小数的差小于k

题目分析:

直接rmq求取,区间最大最小值,枚举每个起点,二分终点,然后对于i点能够满足条件的最远区间到终点,所以贡献r-l+1,求取和就是最后结果

代码如下:

#include <iostream>#include <cstring>#include <cstdio>#include <cmath>#include <algorithm>#define MAX 100007using namespace std;typedef long long LL;int dp[MAX][20];int dp2[MAX][20];int a[MAX];int n,k;void init (){    for ( int i = 0 ; i < n ; i++ )        dp[i][0] = a[i],dp2[i][0] = a[i];    for ( int j = 1; (1<<j) <= n ; j++ )        for ( int i = 0 ; i + (1<<j)-1 < n ; i++ )        {            dp[i][j] = max ( dp[i][j-1] , dp[i+(1<<(j-1))][j-1] );            dp2[i][j] = min ( dp2[i][j-1] , dp2[i+(1<<(j-1))][j-1] );        }}int big ( int l , int r ){    int k = (int)((log(r-l+1)*1.0)/(log(2.0)));    return max ( dp[l][k] , dp[r-(1<<k)+1][k] );}int small ( int l , int r ){    int k = (int)((log(r-l+1)*1.0)/(log(2.0)));    return min ( dp2[l][k] , dp2[r-(1<<k)+1][k] );}bool check ( int x , int mid , int k ){    return big( x , mid )-small ( x , mid ) < k;}int search ( int x, int k ){    int l = x , r = n-1 , mid;    while ( l != r )    {        mid = (l+r+1)>>1;        if ( check ( x , mid , k )) l = mid;        else r = mid-1;    }    return l;}int t;int main ( ){    scanf ( "%d" , &t );    while ( t-- )    {        scanf ( "%d%d" , &n , &k );        for ( int i = 0 ; i < n ; i++ )            scanf ( "%d" , &a[i] );        init();        int i = 0;        LL ans = 0;        while ( i < n )        {            //int x = search ( i , k );            int l = i , r = n-1 , mid;            while ( l != r )            {                mid = (l+r+1)>>1;                if ( check ( i , mid , k )) l = mid;                else r = mid-1;            }            ans += l-i+1;            i++;        }        printf ( "%I64d\n" , ans );    }}


0 0