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);
}
上一篇:Linux(Ubuntu16.04)下添加新用户


下一篇:【linux-centos】php-rdkafka扩展安装