AGC006 D

題意:
給出一個長度爲2*n-1的排列,將除了頭尾兩個數變爲相鄰3個數的中位數,重複n-1次。
像這樣

問最上面的數字是多少。
n<=100000

#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<iostream>
#define N 210000
using namespace std;
int n,m,a[N],b[N],ans,num;
struct node{int l,r,c;}A[N];
int solve(int lim)
{
    for(int i=1;i<=m;i++) b[i]=(a[i]>=lim);
    num=0;
    int i=1;
    while(i<m)
    {
        if(b[i]!=b[i+1]) {i++;continue;}
        A[++num].l=i;A[num].c=b[i];
        while(i<m && b[i+1]==b[i]) i++;
        A[num].r=i;
    }
    if(num==0) return b[1];
    A[0].r=0;
    for(int i=1;i<=num;i++)
    {
        int l=A[i-1].r+1,r=A[i].l-1;
        if(l>r) continue;
        int mid=(l+r)/2;
        A[i-1].r=mid;A[i].l=mid+1;
    }
    int l=A[num].r+1,r=m,mid;
    if(l<=r) {mid=(l+r)/2;A[num].r=mid;}
    for(int i=1;i<=num;i++) if(A[i].l<=n && A[i].r>=n) return A[i].c;
}
int main()
{
    scanf("%d",&n);
    m=2*n-1;
    for(int i=1;i<=m;i++) scanf("%d",&a[i]);
    int l=1,r=m;
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(solve(mid)) ans=mid,l=mid+1;
        else r=mid-1;
    }
    printf("%d\n",ans);
    return 0;
}

題解:
考慮想鏼爺的bc那題一樣,二分一個數,把大於等於他的位置寫1,小於的寫-1,這樣取中位數就變成了模2意義下的加法,統計出底層每個點到最上層的路徑數算一下結果是1還是-1就好。然而算路徑數我只想到了倍增fft,也許比賽時可以打個表>_<
其實我覺得我的模型很棒棒啊
膜了題解的做法,先二分,然後看一張01序列合併的圖
這裏寫圖片描述
發現對於連續的0或1,他會一直向上伸。對於01交替,就會不停變小,直到兩邊的連續序列相交,處理一下每一段最後覆蓋的區間就好。特判全部01交替的情況。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章