码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 6231 (二分+双指针)

时间:2017-11-12 00:59:57      阅读:284      评论:0      收藏:0      [点我收藏+]

标签:++   指针   clu   using   如何   fine   break   close   void   

题意:给一个长度为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 (二分+双指针)

标签:++   指针   clu   using   如何   fine   break   close   void   

原文地址:http://www.cnblogs.com/qswg/p/7820446.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!