[agc006D]Median Pyramid Hard-[二分+乱搞]

Description

题目大意:给你一个长度为n*2-1的排列,将除了该序列头尾的两个数外的其他数(设为i)变为原序列i-1,i,i+1下标数的中位数。求最后的数是什么。例子如下:

        

 

Solution

这道题我们考虑二分(反正我YY了好久也没想出其他做法)。

我们设当前二分到k,要判断答案与k的大小关系。将原排列中<=k的数设为0,反之设为1。

如此我们可以得到一个01序列。

通过分析可得,假如01序列中有两个相邻的数相等,则它们正上方的所有数都与它们相等。(我们可以称之为柱子)

         1    

      _ 1 1 

   _ _ 1 1 _ 

_ _ _ 1 1 _ _

则对于某个排列如果它最上方的数为0,有以下情况:

1,它的第n位是柱子。

2,以它的第n位为中心,左边或者右边只有为0的柱子

3,以它的第n位为中心,两边最近的柱子都为0

4,以它的第n位为中心,两边的柱子分别为0和1,但是0柱子离中心较近。

5,以它的第n位为中心,左右两边都没有柱子,则需要序列第1位为0。

以下为情况4的证明:

1|  1 1 1 1 1 0 0 0 0 0  |0

1|  1 1 1 1 1 0 0 0 0 0  |0

1|  1 1 1 1 0 1 0 0 0 0  |0

1|  1 1 1 0 1 0 1 0 0 0  |0

1|  1 1 0 1 0 1 0 1 0 0  |0

1|  1 0 1 0 1 0 1 0 1 0  |0

1|  0 1 0 1 0 1 0 1 0 1  |0

该图左边是1柱子,右边是0柱子。依图可证明。

其他证明同理。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int n,a[400010],l,r,mid,ans;
bool _get(int x){ return !(x<=mid);}
bool check()
{
    for (int i=1;i<=n-1;i++)
    {
        if (_get(a[n+i-1])==_get(a[n+i])) return _get(a[n+i]);
        if (_get(a[n-i+1])==_get(a[n-i])) return _get(a[n-i+1]);
    }
    return _get(a[1]);
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=2*n-1;i++) scanf("%d",&a[i]);
    l=1;r=2*n-1;
    while (l<=r)
    {
        mid=(l+r)/2;
        if (!check()) r=mid-1,ans=mid;else l=mid+1;
    }
    cout<<ans;
}

 

posted @ 2018-08-15 17:38  _雨后阳光  阅读(470)  评论(0编辑  收藏  举报