题目链接:
题目大意:
给出一个序列,问能找出多少个连续区间,区间内最大最小数的差小于k
题目分析:
直接rmq求取,区间最大最小值,枚举每个起点,二分终点,然后对于i点能够满足条件的最远区间到终点,所以贡献r-l+1,求取和就是最后结果
代码如下:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define MAX 100007
using 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 );
}
}