题目链接:
点击打开链接
题目大意:
给出一个序列,问能找出多少个连续区间,区间内最大最小数的差小于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 ); } }