本弱由于把题目看错,k和m看反了,导致样例一直推不出,还有怀疑题目错误的**行为。
先说下题目意思,给出一个A数组,问所有区间长度大于等于k中,取第k大的数,然后放进B数组中,最后在B数组中在求第m大的数。
分析: 首先暴力去做,1e5的数据量那是妥妥的T了,我们可以先对答案进行二分,然后反向去满足题目的要求。
假设,我们二分出来一个答案为x,那么我们用取尺的思想去得出,我们可以这么想,我们已知了x,我们要从A数组中得到第k大数大于等于x的区间个数,如果区间个数大于了m,说明大于x数太多了,二分出来的x偏小,往后走,否则就往前走。
如何找第k大数大于等于x的区间个数呢,首先从1开始到n,如果a[i]>=x,num++,如果num==k的时候,说明当前区间[1,i]中已经满足第k大的数大于等于x了,i之后的所有区间[1,i+1],[1,i+2].....[1,n]都是满足条件的,所以ans+=(n-i+1). 那么只有这么点吗,其实还有,我们设一个j=1. 如果a[j]<x ,那就说明这个a[j]对结果无影响的,所以只是情况多了n-i+1。条件依然满足。
注意:long long
AC代码:
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <string> #include <vector> #include <map> #include <queue> #include <deque> #include <set> #include <stack> #include <cctype> #include <cmath> #include <cassert> using namespace std; typedef long long ll; const ll mod=1000000007; ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;} ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;} const int N=1e5+100; ll t; ll n,k,m; ll a[N]; bool solve(ll x) { ll num=0; ll ans=0; ll j=1; for(ll i=1;i<=n;i++) { if(a[i]>=x) { num++; } if(num==k) { ans+=(n-i+1); while(a[j]<x) { ans+=(n-i+1); j++; } j++; num--; } } if(ans>=m)return true; else return false; } int main() { scanf("%lld",&t); while(t--) { scanf("%lld%lld%lld",&n,&k,&m); for(ll i=1;i<=n;i++)scanf("%lld",&a[i]); ll l=1; ll r=1e5+1; while(l<r) { ll mid=(l+r)>>1; if(solve(mid))l=mid+1; else r=mid; } printf("%lld\n",l-1); } return 0; }