题目链接: 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]; 5 int dp1[MAX_N][25]; 6 int dp2[MAX_N][25]; 7 long long ans = 0; 8 int N,M,T; 9 void ST(int N) 10 { 11 for(int i=1;i<=N;i++) dp1[i][0] = dp2[i][0] = vec[i]; 12 for(int j=1;(1<<j)<=N;j++) 13 { 14 for(int i=1;i+(1<<j)-1<=N;i++) 15 { 16 dp1[i][j] = max(dp1[i][j-1],dp1[i+(1<<j-1)][j-1]); 17 dp2[i][j] = min(dp2[i][j-1],dp2[i+(1<<j-1)][j-1]); 18 } 19 } 20 } 21 int RMQ(int l,int r) 22 { 23 int k = 0; 24 while(1<<k+1 <= r-l+1) k++; 25 int maxn = max(dp1[l][k],dp1[r-(1<<k)+1][k]); 26 int minn = min(dp2[l][k],dp2[r-(1<<k)+1][k]); 27 return maxn-minn; 28 } 29 int main() 30 { 31 cin>>T; 32 while(T--) 33 { 34 cin>>N>>M; 35 ans = 0; 36 for(int i=1;i<=N;i++) scanf("%d",&vec[i]); 37 ST(N); 38 for(int i=1;i<=N;i++) 39 { 40 int l =i,r = N; 41 while(l<=r) 42 { 43 int mid = (l+r)>>1; 44 if(RMQ(i,mid) < M) l = mid+1; 45 else r = mid-1; 46 } 47 ans += (l-1) - i +1; 48 } 49 cout<<ans<<endl; 50 } 51 return 0; 52 }