1. 程式人生 > >HDU - 5289 Assignment (RMQ+二分)

HDU - 5289 Assignment (RMQ+二分)

color 子序列 void pan acm -- 最小 col bit

題目鏈接: 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 }

HDU - 5289 Assignment (RMQ+二分)