分析:
肯定不能暴力找。(这不是废话嘛。。)
稍微思考一下,我们可以发现区间的单调性。当区间宽度变长时,所谓的区间的价值一定会增大。
于是我们先二分答案,然后可以利用区间的单调性判断答案是否可行。
用Two pointers固定左端点,检查一段区间的价值是否大于二分值。假设[L, R]这个区间的价值大于了二分的答案,那么[L, R + 1]……以后的区间都能够满足要求。这样能够在线性的时间内求出比二分值大的价值的区间数目。
map寄存会TLE,这里离散化了一下。
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 2e5 + 5;
long long N, K;
int a[maxn], b[maxn], c[maxn];
int f[maxn];
long long check(long long mid) {
int p = 1, q = 0;
long long ans = 0;
long long res = 0;
memset(f, 0, sizeof(f));
while (p <= N) {
while (q <= N && res <= mid) {
res += 1ll * f[c[++ q]];
f[c[q]] ++;
}
ans += N - q + 1;
f[c[p]] --;
res -= 1ll * f[c[p ++]];
}
return ans;
}
int main(int argc, char const *argv[]) {
int T; cin>>T;
while (T --) {
cin>>N>>K;
for (int i = 1; i <= N; i ++) {
scanf("%d", a + i);
b[i] = a[i];
}
sort(b + 1, b + N + 1);
int len = unique(b + 1, b + N + 1) - b;
for (int i = 1; i <= N; i ++)
c[i] = lower_bound(b + 1, b + len + 1, a[i]) - b;
long long all = (N + 1) * N / 2;
long long lb = 0, ub = 3e12, res = -1;
// cout<<"threshold "<<all - K<<endl;
while (lb <= ub) {
long long mid = (lb + ub) >> 1;
long long ans = check(mid);
// cout<<mid<<" "<<ans<<endl;
if (ans <= all - K) {
res = mid;
ub = mid - 1;
}
else
lb = mid + 1;
}
cout<<res<<endl;
}
return 0;
}