UVA1335 Beijing Guards

链接

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4081

题解

对于 n 为偶数偶数直接找最大的 r i + r i + 1 ,你可以通过偶数从上往下放,奇数从下往上放构造出一种合法方案,而且显然 r i + r i + 1 就是解的下界
奇数我没想出来怎么处理,看了刘汝佳的题解:第一个人直接从最小的开始放,连续放 1... r 1 ,第二个人从 r 1 + 1 开始连续放 r 2 个,下一个从最大的数开始放,再下一个从最小的数开始放,以此类推,最后第 n 个是从上往下放的,二分上界然后模拟,验证一下中间或者第 n 个有没有发生冲突。
他说这样显然是最优的,虽然我无法证明,不过我觉得这样摆放的确是很优的,这种验证方式也的确符合单调的性质。
谁能严谨地证明这种贪心地正确性?

代码

#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;
}

猜你喜欢

转载自blog.csdn.net/fsahfgsadhsakndas/article/details/81045504
今日推荐