询问所有区间值中第k小的值,肯定不能把所有区间的值求出来,毕竟有n^2个区间。
我们如果先假设一个答案,然后能够找到所有区间里有多少个区间的值小于当前的答案的话,岂不是就可以二分答案了。那么如何去找到小于x的区间有多少个呢,如果你会双指针的话,这里用一下双指针就是再方便不过了,o(n)的扫一遍加上一个桶来统计区间里元素的值就好了。
然后由于元素的值的范围是0到1e9,所有要先离散化一下,然后就做完另外。
代码:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn=2e5+5;
int a[maxn];
int b[maxn];
int ord[maxn];
int book[maxn];
int vis[maxn];
int n, k;
int check(LL x)
{
int i, j, ed=0;
LL sum=0, y, num=0;
memset(book, 0, sizeof(book));
book[ord[ed]]=1;
for(i=0; i<n; i++)
{
while(ed<n && sum<=x)
{
ed++;
y=book[ord[ed]];
sum+=y;
book[ord[ed]]++;
}
// printf("%lld ed%d\n", x, ed);
num+=ed-i;
book[ord[i]]--;
sum-=book[ord[i]];
}
//printf("%lld %d\n", x, num);
return num>=k;
}
int main()
{
int t;
cin>>t;
int i, j;
while(t--)
{
scanf("%d%d", &n, &k);
for(i=0; i<n; i++)
{
scanf("%d", &a[i]);
b[i]=a[i];
}
sort(b, b+n);
int len=unique(b, b+n)-b;
for(i=0; i<n; i++)
{
ord[i]=lower_bound(b, b+len, a[i])-b;
}
// for(i=0; i<n; i++)printf("%d ", ord[i]);printf("\n");
LL l=0, r=n*(n+1)/2;
LL mid;
LL ans=0;
for(i=0; i<100; i++)
{
mid=(l+r)>>1;
if(check(mid))
{
ans=mid;
r=mid-1;
}
else
{
l=mid+1;
}
}
printf("%lld\n", ans);
}
}