In the P.E. class , n students listed in a line on the playground. However, they are not ordered by their height. As you know, some of them are higher, while others are shorter. In this way, let’s define a function called F,which depend on the height of the ith students. The F of the ith student (we can call it Fi) with height hi is the sum of three parts: The first part is a number 1,which means himself The second part is: counting from the i-1th student to the 1st student until some one is shorter than the ith student. The third part is: counting from the i+1th student to the last student until some one is shorter than the ith student. For example, if the heights of the students are: 2 3 2 4 5 Then F(1)=1+0+4=5,F(2)=1+0+0=1,F(3)=1+2+2=5,F(4)=1+0+1=2,F(5)=1+0+0=1 Now the problem is very simple,just tell me the the kth large one among all the Fi.
The input contains several test cases. The first line contains an integer T(T ≤ 100) denoting the number of test cases. Then T test cases follow. Each of them begins with a line containing two numbers n and k(1 ≤ k≤n ≤ 100000).The next line contains n integers h1,h2,..., hn where 1 ≤ hi ≤ 1000000000 is the height of i th student.
For each test case, output the kth large one among all the Fi.
2 5 2 1 2 2 3 3 5 2 2 3 2 4 5
4 5
题意:
给出n,k,n个数hi
就是n个人,当前的人为第i个时,高度为hi,
先从i-1找到1,直到找到一个比它小的数,记下查找的步数a
然后从i+1开始向右找到n,直到找到另一个比它小的数,记下查找的步数b
然后第i个数的函数值Fi就是a+b+1
n个人有n个F值
求出第k大的F值
1 ≤ hi ≤ 1000000000 ,n and k(1 ≤ k≤n ≤ 100000).
这题应该用单调栈,不能二分,二分找到的是离a[i]最远的比他小的数,而题目要求的是最近的!
线段树也可以做nlogn
以下 是单调栈代码:
//Problem(M25):The Kth Large #include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <iostream> #include <queue> #include <stack> #include <set> #include <vector> using namespace std; __int64 tm[200005]; __int64 tm2[200005]; __int64 l_ans[200005]; __int64 r_ans[200005]; __int64 tmp[200005]; struct node { __int64 x; __int64 num; node(){} node(__int64 a,__int64 b) { x=a;num=b; } }; node ans[200005]; __int64 res[200005]; stack <node> sb; stack <node> sb2; __int64 max(__int64 a,__int64 b) {return a<b?b:a;} __int64 cmp(node a,node b) { if (a.x!=b.x) return a.x>b.x; else return a.num>b.num; } int main() { __int64 t,n,k; scanf("%I64d",&t); while(t--) { scanf("%I64d%I64d",&n,&k); while(!sb.empty()) sb.pop(); while(!sb2.empty()) sb2.pop(); __int64 i; // scanf("%I64d",&n); for (i=1;i<=n;i++) { scanf("%I64d",&tm[i]); tm2[n-i+1]=tm[i]; } //**************************************** 计算每个数到左边第一个比之小的数的距离 l_ans[1]=0; sb.push(node(tm[1],1)); for (i=2;i<=n;i++) { if (tm[i]>sb.top().x) l_ans[i]=i-sb.top().num-1; else { while(!sb.empty()&&tm[i]<=sb.top().x) sb.pop(); if (sb.empty()) l_ans[i]=i-1; else l_ans[i]=i-sb.top().num-1; } sb.push(node(tm[i],i)); } //**************************************** 计算每个数到右边第一个比之小的数的距离 r_ans[1]=0; sb2.push(node(tm2[1],1)); for (i=2;i<=n;i++) { if (tm2[i]>sb2.top().x) r_ans[i]=i-sb2.top().num-1; else { while(!sb2.empty()&&tm2[i]<=sb2.top().x) sb2.pop(); if (sb2.empty()) r_ans[i]=i-1; else r_ans[i]=i-sb2.top().num-1; } sb2.push(node(tm2[i],i)); } ///**********翻转r_ans for (i=1;i<=n;i++) { tmp[n-i+1]=r_ans[i]; } for (i=1;i<=n;i++) { r_ans[i]=tmp[i]; } for (i=1;i<=n;i++) { res[i]=l_ans[i]+r_ans[i]+1; } sort(res+1,res+1+n); printf("%d",res[n-k+1]); printf("\n"); } return 0; }
以前二分写的错误代码。 不过不了样例【 4 3 2 1】这种
//Problem(M25):The Kth Large #include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <iostream> #include <queue> #include <map> #include <set> #include <vector> using namespace std; __int64 tm[100005]; __int64 tm2[100005]; __int64 minn[100005]; __int64 r_minn[100005]; __int64 l_dist[100005]; __int64 backup_r_dist[100005]; __int64 r_dist[100005]; __int64 ans[100005]; int main() { __int64 t,n,k; scanf("%I64d",&t); while(t--) { __int64 i; scanf("%I64d%I64d",&n,&k); for (i=1;i<=n;i++) { scanf("%I64d",&tm[i]); tm2[n-i+1]=tm[i]; } __int64 min_mark=tm[n]; minn[n]=tm[n]; for (i=n-1;i>=1;i--) { if (tm[i]<min_mark) min_mark=tm[i]; minn[i]=min_mark; } __int64 it,tmp; l_dist[n]=0; //最后一个数一定为0; for (i=1;i<n;i++) { it=lower_bound(minn+i+1,minn+1+n,tm[i])-(minn); if (it==n+1&&n!=i) //不存在比tm[i]大的数,全部数都比tm[i]小,按题意取最近的,dist=1; l_dist[i]=n-i; else { if (it!=i+1) it--;//防止越界 if(tm[i]>minn[it]) //存在比tm[i]小的数 { tmp=upper_bound(minn+i+1,minn+1+n,minn[it])-(minn);//找到大于minn[it]的第一个 tmp--; l_dist[i]=tmp-i-1; } else //不存在比tm[i]小的数 { l_dist[i]=n-i; } } } min_mark=tm2[n]; r_minn[n]=tm2[n]; for (i=n-1;i>=1;i--) { if (tm2[i]<min_mark) min_mark=tm2[i]; r_minn[i]=min_mark; } //__int64 it,tmp; backup_r_dist[n]=0; for (i=1;i<n;i++) { it=lower_bound(r_minn+i+1,r_minn+1+n,tm2[i])-(r_minn); if (it==n+1) //不存在比tm2[i]大的数,全都比他小 backup_r_dist[i]=0; else { if (it!=i+1) it--;//防止越界 if(tm2[i]>r_minn[it]) //存在比tm2[i]小的数 { tmp=upper_bound(r_minn+i+1,r_minn+1+n,r_minn[it])-(r_minn);//找到大于r_minn[it]的第一个 tmp--; backup_r_dist[i]=tmp-i-1; } else backup_r_dist[i]=i-1;//不存在比他小的 } } for (i=1;i<=n;i++) { r_dist[n-i+1]=backup_r_dist[i]; } for (i=1;i<=n;i++) { ans[i]=r_dist[i]+l_dist[i]+1; } sort(ans+1,ans+1+n); printf("%I64d\n",ans[n-k+1]); } return 0; }