hihocoder 1483 區間價值
阿新 • • 發佈:2019-02-04
分析:
肯定不能暴力找。(這不是廢話嘛。。)
稍微思考一下,我們可以發現區間的單調性。當區間寬度變長時,所謂的區間的價值一定會增大。
於是我們先二分答案,然後可以利用區間的單調性判斷答案是否可行。
用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;
}