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.
 

 

Input
The first line is the number of test cases.

For each test case, the first line contains three positive numbers N(1N105),K(1KN),M . The second line contains N numbers Ai(1Ai109) .

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代码:
 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 }
View Code

 

 
 
 
 
 
 
posted @ 2017-11-25 23:20  euzmin  阅读(219)  评论(0编辑  收藏  举报