ARC092E Both Sides Merger

题意

给你一个长度为 \(n\) 的序列 \(a\)

有两种操作:

  1. 选择一个端点的数,删除

  2. 选择一个非端点的数,将其变为相邻左右两数之和,删去左右两边的数。

若干次操作后序列只剩下一个数,求最大值,并输出方案。

\(2 \leq n \leq 1000,|a_i| \leq 10^9\)

传送门

思路

首先对于二操作,其实一个数所属位置的奇偶性不会改变,奇数位加到奇数位,偶数位加到偶数位,所以最终的最大值中,会由偶数位正数相加和奇数位正数相加产生。

为什么是正数呢?因为对于负数,中间的我们只需要对它进行二操作,将三个数并成一个,直到两边都是正数为止,负数就消失了。两边的就一直删到需要相应位的正数为止即可。然后我们就得到了一个一个要一个不要的数列,只需要对第二个位置一直做操作二即可。

注意特判全部都是负数的情况。

#include <bits/stdc++.h>
using std::max; 
const int N=1005;
long long sum1,sum2;
int a[N],ans[N],n,cnt,now,l,r,t;
int main(){
	scanf("%d",&n);
	for (int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		if (i&1) sum1+=max(a[i],0);
		else sum2+=max(a[i],0);
	}
	if (sum1==0 && sum2==0){
		int mx=1;
		for (int i=1;i<=n;i++) if (a[i]>a[mx]) mx=i;
		printf("%d\n%d\n",a[mx],n-1);
		for (int i=n;i>mx;i--) printf("%d\n",i);
		for (int i=1;i<mx;i++) printf("%d\n",1);
		return 0; 
	}
	if (sum1>sum2){
		t=1;
		printf("%lld\n",sum1);	
	} else t=0,printf("%lld\n",sum2);
	int i=n;
	for (;(i%2)!=t || a[i]<0;i--) ans[++cnt]=i;
	r=i;
	i=1;
	for (;(i%2)!=t || a[i]<0;i++) ans[++cnt]=1;
	l=i;
	for (i=l;i<=r;i+=2) 
		if (a[i]<0 && (i%2)==t) ans[++cnt]=now*2+1;
		else now++;
	for (int i=1;i<now;i++) ans[++cnt]=2;
	printf("%d\n",cnt);
	for (int i=1;i<=cnt;i++) printf("%d\n",ans[i]); 
}
posted @ 2020-07-27 20:40  flyfeather  阅读(153)  评论(0编辑  收藏  举报