ARC092E Both Sides Merger
题意
给你一个长度为 \(n\) 的序列 \(a\)。
有两种操作:
-
选择一个端点的数,删除
-
选择一个非端点的数,将其变为相邻左右两数之和,删去左右两边的数。
若干次操作后序列只剩下一个数,求最大值,并输出方案。
\(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]);
}
* 生而自由 爱而无畏 *