链接
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4081
题解
对于
为偶数偶数直接找最大的
,你可以通过偶数从上往下放,奇数从下往上放构造出一种合法方案,而且显然
就是解的下界
奇数我没想出来怎么处理,看了刘汝佳的题解:第一个人直接从最小的开始放,连续放
,第二个人从
开始连续放
个,下一个从最大的数开始放,再下一个从最小的数开始放,以此类推,最后第
个是从上往下放的,二分上界然后模拟,验证一下中间或者第
个有没有发生冲突。
他说这样显然是最优的,虽然我无法证明,不过我觉得这样摆放的确是很优的,这种验证方式也的确符合单调的性质。
谁能严谨地证明这种贪心地正确性?
代码
#include <cstdio>
#include <algorithm>
#include <cstring>
#define clear(x) memset(x,0,sizeof(x))
#define maxn 100010
using namespace std;
int n, r[maxn], a[maxn], b[maxn], c[maxn];
bool check(int lim)
{
int i;
clear(a), clear(b), clear(c);
c[1]=r[1];
c[2]=0,b[2]=r[1]+1, a[2]=r[1]+r[2];
for(i=3;i<=n;i++)
{
if(i&1) //ÆæÊýÍùÉÏÈ¡
{
if(a[i-1]==0)
{
c[i]=lim-r[i]+1;
if(c[i]<=c[i-1])return false;
}
else if(r[i]<=lim-a[i-1])
{
c[i]=lim-r[i]+1;
}
else
{
c[i]=a[i-1]+1;
b[i]=b[i-1]-1;
a[i]=b[i]-(r[i]-(lim-c[i]+1))+1;
if(a[i]<=c[i-1])return false;
}
}
else //żÊýÍùÏÂÈ¡
{
if(a[i-1]==0)
{
c[i]=r[i];
if(c[i]>=c[i-1])return false;
}
else if(r[i]<a[i-1])
{
c[i]=r[i];
}
else
{
c[i]=a[i-1]-1;
b[i]=b[i-1]+1;
a[i]=b[i]+r[i]-c[i]-1;
if(a[i]>=c[i-1])return false;
}
}
}
if(a[n])return a[n]>c[1];
return c[n]>c[1];
}
int odd()
{
int i, l=-1;
if(n==1)return r[1];
for(i=1;i<n;i++)l=max(l,r[i]+r[i+1]);l=max(l,r[1]+r[n]);
int r=maxn<<2, mid=(l+r)>>1;
while(l^r)
{
if(check(mid))r=mid;
else l=mid+1;
mid=(l+r)>>1;
}
return l;
}
int even()
{
int ans=-1, i;
for(i=1;i<n;i++)ans=max(ans,r[i]+r[i+1]);
ans=max(ans,r[1]+r[n]);
return ans;
}
int main()
{
int t, i;
for(scanf("%d",&n);n;scanf("%d",&n))
{
for(i=1;i<=n;i++)scanf("%d",r+i);
if(n&1)printf("%d\n",odd());
else printf("%d\n",even());
}
return 0;
}