1. 程式人生 > >HDU 6231 (二分+雙指針)

HDU 6231 (二分+雙指針)

div 技術分享 ace += hdu blog 所有 sca pan

題意:給一個長度為n的數組,問在由這個數組的所有的區間第k小組成B數組中,第m大元素是多少

解法:這題較難的地方在於轉化思維。如果去求所有區間的第k小,最壞復雜度是O(n*n)肯定超時。

這題正確的解法是二分一個最大的x,且這個x滿足有大於等於m個區間的第k小大於等於x.。

所以關鍵在於,如何求有多少個區間的第k小大於等於x.

一個區間第k小要大於等於x,則這個區間至少要有k個數大於等於x..

我們枚舉區間的左端點L。對於每個左端L,可以找一個最小的r使得,當右端點大於等於r時,[L,r]有k個數大於等於x。所以L為左端點的區間中滿足要求的區間數有 n-r+1個

而這個r關於l顯然是有單調性的,所以可以考慮用雙指針O(n)求出所有r.。

所以算法復雜度O(nlogn)

技術分享
 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<time.h>
 4 #include<algorithm>
 5 #include<vector>
 6 #include<set>
 7 #define ll long long
 8 using namespace std;
 9 int a[1000005],b[1000005];
10 long long num;
11 int check(int n,int k,int m)
12 {
13 long long sum=0; 14 int i,j=0,s=0; 15 for(i=1;i<=n;i++) 16 { 17 while(s<k&&j<=n) 18 { 19 j++; 20 if(a[j]>=m) 21 s++; 22 } 23 if(j>n) 24 break; 25 sum+=n-j+1; 26 if
(a[i]>=m) 27 s--; 28 } 29 // printf("%d %d\n",m,sum); 30 return sum<num; 31 } 32 void find(int n,int k) 33 { 34 int l=1,r=n+1,m; 35 while(l+1<r) 36 { 37 m=(l+r)/2; 38 if(check(n,k,b[m])) 39 r=m; 40 else 41 l=m; 42 } 43 printf("%d\n",b[l]); 44 } 45 int main() 46 { 47 int i,j,n,t,m,k,l,r; 48 scanf("%d",&t); 49 while(t--) 50 { 51 scanf("%d%d%I64d",&n,&k,&num); 52 for(i=1;i<=n;i++) 53 { 54 scanf("%d",&a[i]); 55 b[i]=a[i]; 56 } 57 sort(b+1,b+n+1); 58 find(n,k); 59 } 60 return 0; 61 }
Ac代碼

HDU 6231 (二分+雙指針)