给定 \(n\) 个二元组 \((s_i,v_i)\) 和正整数 \(d_s,d_v\),求选择 \(m\) 个二元组的 \((\sum v)^{d_v}-(\max s-\min s)^{d_s}\) 的最大值。
\(n\le 2\cdot 10^5\),\(m\le 50\),\(d_s,d_v\le 2\),\(1\le s_i,v_i\le 10^7\)。
显然按 \(s\) 排序之后就变成了选一个区间 \([l,r]\),贡献是这一段的前 \(m\) 大的 \(v\) 之和的 \(d_v\) 减去 \((s_r-s_l)^{d_s}\)。
然后就被教育了:先枚举所有长度 \(\le m\) 的区间,然后从小到大枚举第 \(m\) 大的 \(v\) 是哪个,用链表维护比 \(\ge\) 当前 \(v\) 的二元组,只用看向左向右 \(m\) 个,枚举 \(m\) 个区间计算答案。
时间复杂度 \(O(nm)\)。
#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef pair<int, int> pii;
typedef long long LL;
const int N = 200003, M = 103;
template<typename T>
void rd(T &x){
int ch = getchar(); x = 0;
for(;ch < '0' || ch > '9';ch = getchar());
for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
}
template<typename T>
bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
int n, m, k, ds, dv, id[N], lst[N], nxt[N], b[M];
pii a[N];
LL ans, sum[M];
LL valv(LL v){return dv == 1 ? v : v * v;}
LL vals(LL s){return ds == 1 ? s : s * s;}
int main(){
rd(n); rd(m); rd(ds); rd(dv);
for(int i = 1;i <= n;++ i){
rd(a[i].fi); rd(a[i].se);
}
sort(a+1, a+n+1);
for(int i = 1;i <= n;++ i){
LL s = a[i].se;
for(int j = i;j < i+m && j <= n;s += a[++j].se)
chmax(ans, valv(s) - vals(a[j].fi-a[i].fi));
}
for(int i = 1;i <= n;++ i){
lst[i] = i-1; nxt[i] = i+1; id[i] = i;
}
sort(id+1, id+n+1, [&](int x, int y){return a[x].se==a[y].se ? x<y : a[x].se<a[y].se;});
for(int _ = 1;_ <= n-m+1;++ _){
k = 0; int i = id[_];
for(int j = 1, p = lst[i];j < m && p;++ j, p = lst[p]) b[++k] = p;
reverse(b+1, b+k+1); b[++k] = i;
for(int j = 1, p = nxt[i];j < m && p <= n;++ j, p = nxt[p]) b[++k] = p;
for(int j = 1;j <= k;++ j) sum[j] = sum[j-1] + a[b[j]].se;
for(int j = m;j <= k;++ j)
chmax(ans, valv(sum[j]-sum[j-m]) - vals(a[b[j]].fi-a[b[j-m+1]].fi));
lst[nxt[i]] = lst[i]; nxt[lst[i]] = nxt[i];
}
printf("%lld\n", ans);
}