HDU 5289 Assignment (二分+RMQ)

来源:互联网 发布:航天开票软件开票流程 编辑:程序博客网 时间:2024/04/29 22:39

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5289

题        意:给T组数据,然后每组一个n和k,表示n个数,k表示最大允许的能力差,接下来n个数表示n个人的能力,求能力差在k之内的区间有几个。

思        路:预处理出区间[i,j]中的最大值最小值(用RMQ算法),然后枚举左端点l,二分出符合条件的右端点r,以l为左端点,j为右端点(l<=j<=r)的符合条件的集合为(r-l+1)。

代码如下:

#include <iostream>using namespace std;#include <string.h>#include <stdio.h>#include <cmath>#include <algorithm>#define maxn 200005typedef __int64 LL;int a[maxn];int mx[maxn][30],mi[maxn][30];int n, k;void RMQ()//RMQ算法的处理与存储{    for( int i = 1; i <= n; i ++ )        mx[i][0] = mi[i][0] = a[i];    for( int j = 1; (1<<j) <= n; j ++ )    {        for( int i = 1; i + (1<<j) - 1 <= n; i ++ )        {            int p = 1<<(j-1);            mx[i][j] = max( mx[i][j-1], mx[i+p][j-1] );            mi[i][j] = min( mi[i][j-1], mi[i+p][j-1] );        }    }}int q( int i, int j )//RMQ算法的查询{    int k = log2( j-i+1.0 );//在区间的长度为j - i + 1的区间内查询最值    int maxx = max( mx[i][k], mx[j-(1<<k)+1][k] );    int minx = min( mi[i][k], mi[j-(1<<k)+1][k] );    return maxx - minx;}int main(){    int T;    scanf ( "%d", &T );    while( T-- )    {        scanf ( "%d %d", &n, &k );        for( int i = 1; i <= n; i ++ )            scanf ( "%d", &a[i] );        RMQ();        LL ans = 0;        for( int i = 1; i <= n; i ++ )        {            int l = i, r = n;            while( l + 1 < r )            {                int m = ( l+r ) / 2;                if( q(i,m) < k ) l = m;//条件成立更新左值                else r = m;            }            //cout<<i<<l<<" "<<""<<""<<""<<endl;            if (q(i, r) < k)                ans += (r * 1LL - i + 1);            else ans += (l * 1LL - i + 1);        }        printf( "%I64d\n", ans );    }    return 0;}

0 0
原创粉丝点击