agc026F

题目大意

n个数,AB交替取走其中一个(取完后位置不变),取的数要和上一个人取得位置相邻,A第一次取或剩下没有相邻的则可以任意取

求当AB都最大化其所取的数之和时的最终结果

n<=3e5,ai<=1e3

题解

不会

当n为偶数时A只会取第一个或者最后一个,然后AB交替取,否则如果取中间的话会分成奇偶两边,B可以取偶数那边来获得另一边的先手,这样对于A来说比直接取更劣

当n为奇数时根据上面可知A只会取偶数位的,然后B取走左/右剩下的,如此直到某个时刻A取走当前区间的第一个

设最后的区间为[l,r],那么A取的是[1,l-1]偶+[l,r]奇+[r+1,n]偶

先取走所有偶数的,变成把一个区间取的奇偶反转,考虑二分答案判断

那么存在多个合法的最终区间,显然B会尽量把这些区间破坏掉,但如果存在一种区间集合{[l[i],r[i]]}满足l[1]=1,r[k]=n,r[i]+2=l[i+1],这样B就搞不了A了,A只需要取两个区间中间的,无论B往那边取最后都会剩下一个

把贡献拆开后维护合法点的min(sumi)即可判断

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define inf 2147483647
#define ll long long
//#define file
using namespace std;

int a[300001],n,i,j,k,l,L,R,Mid,ans,sum;

bool pd(int t)
{
	int i,j,k,l,mn=0;
	
	fo(i,1,n)
	if ((i&1) && a[i]-mn>=t)
	{
		if (i==n) return 1;
		mn=min(mn,a[i+1]);
	}
	return 0;
}

int main()
{
	#ifdef file
	freopen("agc026F.in","r",stdin);
	#endif
	
	scanf("%d",&n);
	fo(i,1,n) scanf("%d",&a[i]),sum+=a[i];
	
	if (!(n&1))
	{
		fo(i,1,n) ans+=(i&1)*a[i];
		ans=max(ans,sum-ans);
	}
	else
	{
		fo(i,1,n) ans+=(!(i&1))*a[i],a[i]=a[i]*((i&1)*2-1)+a[i-1];
		L=ans,R=sum;
		
		while (L<R)
		{
			Mid=(L+R)/2;
			if (pd(Mid-ans))
			L=Mid+1; else R=Mid;
		}
		L-=!pd(L-ans),ans=L;
	}
	printf("%d %d
",ans,sum-ans);
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}
原文地址:https://www.cnblogs.com/gmh77/p/13865774.html