hdu 6231
K-th Number
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 518 Accepted Submission(s): 213
Problem Description
Alice are given an array A[1..N]
with N
numbers.
Now Alice want to build an array B by a parameter K as following rules:
Initially, the array B is empty. Consider each interval in array A. If the length of this interval is less than K , then ignore this interval. Otherwise, find the K -th largest number in this interval and add this number into array B .
In fact Alice doesn't care each element in the array B. She only wants to know the M -th largest element in the array B . Please help her to find this number.
Now Alice want to build an array B by a parameter K as following rules:
Initially, the array B is empty. Consider each interval in array A. If the length of this interval is less than K , then ignore this interval. Otherwise, find the K -th largest number in this interval and add this number into array B .
In fact Alice doesn't care each element in the array B. She only wants to know the M -th largest element in the array B . Please help her to find this number.
Input
The first line is the number of test cases.
For each test case, the first line contains three positive numbers N(1≤N≤105),K(1≤K≤N),M . The second line contains N numbers Ai(1≤Ai≤109) .
It's guaranteed that M is not greater than the length of the array B.
For each test case, the first line contains three positive numbers N(1≤N≤105),K(1≤K≤N),M . The second line contains N numbers Ai(1≤Ai≤109) .
It's guaranteed that M is not greater than the length of the array B.
Output
For each test case, output a single line containing the M
-th largest element in the array B
.
Sample Input
2
5 3 2
2 3 1 5 4
3 3 1
5 8 2
Sample Output
3
2
(这真是道好题啊
题意:给定n个数,取 这n个数能组成的 所有长度不小于k的 区间 的第k大的数,把这些数放在b数组里,求b中第m大的数。
解题思路:把所有的区间第K大放到一个新的数组中,然后排序,输出第M大。我二分枚举这个最后的第M大,假设为X,那么我们需要只考虑大于等于X的数字。于是相当于我们只需要判断在这个新数组中,大于等于X的数字的数量是否大于M,也即第K大大于等于X的区间的数量是否大于M。最后变成了统计第K大大于X的区间。模糊化处理之后,我们发现,如果用0、1替代,我们就能通过区间和来判定该区间的第K大是否大于等于X。如果区间和大于等于K,那么第K大就大于等于X。统计数量也相对简单了很多。我们枚举左端点,然后找右端点,知道找到一个点恰好区间和为K,那么以这个点以及这个点之后的所有点为右端点的区间第K大肯定大于等于X。这样子做看似还是O(N^2)的,但是我们发现,当左端点右移一格之后,这个右端点的最小值是不下降的,也就是说可以用类似离线处理的方法,做到用O(N)的复杂度统计。于是此题就迎刃而解了,需要注意的是,这个M可能比较大,需要用LL,然后统计区间的时候也要用LL。
以上是参考博客中的思路,参考博客:http://blog.csdn.net/u013534123/article/details/78509522?locationNum=8&fps=1
也就是说,如果x大于真正的答案,那么满足有k个数大于等于x的区间肯定不到m个,反之肯定多于m个(其实也不一定,比如当所有的数都相等的时候,就不一定。参考博客为了排除这个可能,用了map,也可以只需找到刚刚满足区间和大于等于m的x值便是答案,这是我的做法
附ac代码:
View Code
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <set> 5 using namespace std; 6 typedef long long ll; 7 const int maxn = 1e5+10; 8 int nu[maxn]; 9 int num[maxn]; 10 int flag[maxn]; 11 ll m; 12 int ans; 13 ll cnt; 14 int n,k; 15 ll check(int mid) 16 { 17 ans=0,cnt=0; 18 int u=num[mid]; 19 for(int i=1;i<=n;++i) 20 { 21 if(nu[i]>=u) 22 flag[i]=1; 23 else flag[i]=0; 24 } 25 int ll=1,rr=0; 26 for(ll=1;ll<=n;++ll) //尺取法 27 { 28 29 while(rr<=n && ans<k) 30 { 31 rr++; 32 if(flag[rr]) ans++; 33 34 } 35 if(rr==n+1) 36 break; 37 cnt+=n-rr+1; 38 if(flag[ll]) 39 ans--; 40 } 41 return cnt; 42 } 43 int main() 44 { 45 int t; 46 47 scanf("%d",&t); 48 while(t--) 49 { 50 scanf("%d %d %lld",&n,&k,&m); 51 for(int i=1;i<=n;++i) 52 { 53 scanf("%d",&nu[i]); 54 num[i]=nu[i]; 55 } 56 sort(num+1,num+n+1); 57 int l=1,r=n; 58 int ff=0; 59 while(l<=r) 60 { 61 int mid=(l+r)/2; 62 if(check(mid)>=m) l=mid+1; 63 else r=mid-1; 64 } 65 // printf("%d %d\n",l,r); 66 printf("%d\n",num[r]);//二分的上界,第一个满足check(mid)>=m的值 67 } 68 return 0; 69 }