1. 程式人生 > 其它 >UOJ386【UNR #3】鴿子固定器【ad-hoc,連結串列】

UOJ386【UNR #3】鴿子固定器【ad-hoc,連結串列】

給定 \(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);
}