[PA 2010] Termites

[PA 2010] Termites

整个结构可以被刻画成 \(\geq 0\) 个双端队列和 \(\leq 2\) 个栈,每次可以选择一个元素弹出。

一个简单的策略,每次选择最大的数弹出,但是这样显然错误,比如 \([0,1,2,10,3,0]\)。

考虑这种情况出现在取了 \(x\) 后发现把 \(y \geq x\) 让给了对面,这是我们不希望看到的。

也就是说,如果存在 \(x \leq y \geq z\),则先手无论如何取都会将 \(y\) 让给对方。

此时先手得到 \(x+z\),后手得到 \(y\),故可以将其看作一个 \(x+z-y\) 的物品。

不断合并之后得到单谷序列,在单谷序列上这个做法显然是有道理的,可以 \(O(n \log n)\)。

然而有 stack,将两个 stack 的底端拼在一起,中间加入 \(-\infty\) 即可。

//Ad astra per aspera
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
long long a[1000010],b[1000010],c[1000010],stk[1000010],top;
int n_b,n_c;
int key_pos[1000010][2],key_cnt;
struct Node{
	int num1,num2;
};
bool operator <(const Node &lhs,const Node &rhs){
	return b[key_pos[lhs.num1][lhs.num2]]<b[key_pos[rhs.num1][rhs.num2]];
}
void add(){
	top=0;
	for(int i=1;i<=n_c;i++){
		while(top>=2  &&  stk[top-1]<=stk[top]  &&  stk[top]>=c[i]){
			c[i]+=stk[top-1]-stk[top];
			top-=2;
		}
		stk[++top]=c[i];
	}
	if(top){
		key_cnt++;
		key_pos[key_cnt][0]=0x3f3f3f3f;
		key_pos[key_cnt][1]=-0x3f3f3f3f;
		for(int i=1;i<=top;i++){
			n_b++;
			b[n_b]=stk[i];
			key_pos[key_cnt][0]=min(key_pos[key_cnt][0],n_b);
			key_pos[key_cnt][1]=max(key_pos[key_cnt][1],n_b);
		}
	}
}
int main(){
	long long sum=0;
	int n,min_0=0x3f3f3f3f,max_0=-0x3f3f3f3f;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
		sum+=a[i];
		if(a[i]==0){
			min_0=min(min_0,i);
			max_0=max(max_0,i);
		}
	}
	int lst_pos=min_0;
	for(int i=min_0+1;i<=max_0;i++){
		if(a[i]==0){
			n_c=0;
			for(int j=lst_pos+1;j<=i-1;j++){
				c[++n_c]=a[j];
			}
			add();
			lst_pos=i;
		}
	}
	n_c=0;
	for(int i=max_0+1;i<=n;i++){
		c[++n_c]=a[i];
	}
	c[++n_c]=-0x3f3f3f3f3f3f3f3f;
	for(int i=1;i<=min_0-1;i++){
		c[++n_c]=a[i];
	}
	add();
	priority_queue<Node> pq;
	for(int i=1;i<=key_cnt;i++){
		pq.push((Node){i,0});
		pq.push((Node){i,1});
	}
	long long d=0;
	bool flg=true;
	while(!pq.empty()){
		int id=pq.top().num1,cmd=pq.top().num2;
		pq.pop();
		if(key_pos[id][0]>key_pos[id][1]){
			continue;
		}
		long long num;
		if(cmd==0){
			num=b[key_pos[id][0]++];
		}
		else{
			num=b[key_pos[id][1]--];
		}
		if(flg){
			d+=num;
		}
		else{
			d-=num;
		}
		if(key_pos[id][0]<=key_pos[id][1]){
			if(cmd==0){
				pq.push((Node){id,0});
			}
			if(cmd==1){
				pq.push((Node){id,1});
			}
		}
		flg=!flg;
	}
	if(d<0){
		d+=0x3f3f3f3f3f3f3f3f;
	}
	else{
		d-=0x3f3f3f3f3f3f3f3f;
	}
	printf("%lld %lld",(sum+d)/2,(sum-d)/2);
	return 0;
}
posted @ 2026-08-17 17:15  Oken喵~  阅读(9)  评论(0)    收藏  举报