本弱由于把题目看错,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;
}

京公网安备 11010502036488号