集训队作业2018:GAME(并查集)

本文介绍了一种使用DP算法解决特定问题的高效方法,通过维护一个动态的折线来实现O(|sum|)时间复杂度的解决方案,同时探讨了潜在的O(nlogn)优化可能性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:
在这里插入图片描述

题解:
把这个DP式子给列出来:
fi=si+max⁡j{2∗aj−sj−fj}f_i = s_i + \max_j \{ 2*a_j-s_j- f_j\}fi=si+jmax{2ajsjfj}

把这个后缀max⁡\maxmax记为mmm的话,每次就是m=max⁡{m,−2∗si−1−m}m=\max\{m,-2*s_{i-1}-m\}m=max{m,2si1m},考虑对于初始的每个mmm都维护一下,发现是条折线,维护一下这个折线,每次可以把小的一半合并到另一半去,于是就可以在O(∣sum∣)O(|sum|)O(sum)的时间内做完了(感觉这道题可以O(nlog⁡n)O(n \log n)O(nlogn)做,懒得想了)。

#include <bits/stdc++.h>
using namespace std;

const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}

const int N=1e6+50;
int n,Q,a[N],s[N],anc[N];
int k,b,l,r;
inline int ga(int x) {return (anc[x]==x) ? x : (anc[x]=ga(anc[x]));}
inline int merge(int x,int y) {anc[ga(x)]=ga(y);}
inline int solve() {
	if(a[n]>s[n-1]) return a[n]-s[n-1];
	for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
	int mx=2*a[n]-s[n];
	for(int i=n-1;i>=1;i--) 
		mx=max(mx,-2*s[i]-mx);
	return mx;
}
int main() {
	n=rd();
	for(int i=1;i<n;i++) a[i]=rd(), s[i]=s[i-1]+a[i];
	for(int i=0;i<=s[n-1];i++) anc[i]=i;
	l=0, r=s[n-1]; k=1,b=-s[n-1];
	for(int i=n-2;~i;i--) {
		int v=-s[i];
		int x=(v-b)/k;
		if(x<=l || x>=r) {
			if(max(k*l+b,k*r+b)<=v) {
				v=2*v-k*l-b;
				k=-k; b=v-k*l;
			}
			continue;
		}
		if((x-l)<=(r-x)) {
			if(k==-1) b=k*x+b-x, k=1;
			for(int i=l;i<x;i++) merge(i,2*x-i);
			l=x;
		} else {
			if(k==1) b=k*x+b+x, k=-1;
			for(int i=x+1;i<=r;i++) merge(i,2*x-i);
			r=x;
		}
	}
	Q=rd();
	while(Q--) {
		int x=rd();
		if(x>=s[n-1]) printf("%d ",x-s[n-1]);
		else printf("%d ",k*ga(x)+b);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值