zoukankan      html  css  js  c++  java
  • 【题解】Dvoniz [COCI2011]

    【题解】Dvoniz [COCI2011]

    传送门:( ext{Dvoniz [COCI2011] [P5922]})

    数据( ext{COCI}) 官网 提供。

    【题目描述】

    对于一个长度为 (2 imes K) 的序列,如果它的前 (K) 个元素之和小于等于 (S) 且后 (K) 个之和也小于等于 (S),我们则称之为 ( ext{interesting})。现给定一个长度为 (N) 的序列 (a),要求输出以每个元素开头能找到的最长 ( ext{interesting}) 序列的长度。

    【输入】

    第一行两个整数 (N,S)

    接下来 (N) 行,每行一个正整数,第 (i) 行表示序列中的第 (i) 个元素 (a_i)

    【输出】

    输出共 (N) 行,每行一个整数,第 (i) 行表示以 (a_i) 开头的最长的 ( ext{interesting})序列。如果不存在,则输出 (0)

    【样例】

    样例输入:
    5 10000
    1
    1
    1
    1
    1
    
    样例输出:
    4
    4
    2
    2
    0
    

    【数据范围】

    (100 \%:) (2 leqslant N leqslant 10^5,) (1 leqslant S,a_i leqslant 2 imes 10^9)


    【分析】

    一道灰常 ( ext{interesting}) 的题。

    蒟蒻英语差没有细看官方题解,貌似是 (O(nlogn))(set),我自己 (yy) 了一种 (O(n)) 的神奇算法。

    设以 (a[i]) 为起点的最长合法序列的中点为 (mid_i)(前半段为 ([i,mid]),后半段为 ([mid+1,mid*2-i+1])),则 (ans_i=2(mid_{i}-i+1))

    假设现已求出了 (mid_{i-1}),考虑 (mid_i) 与之有何联系,是否可以继承,如图:

    由于 (mid_{i-1}) 左右两边的绿色部分都小于等于 (S),那么向前推移了一位的 (i)(mid_{i-1}) 为中点也可以构成合法序列,如下图(易知两边的蓝色部分都一定小于等于 (S) ):

    所以对于任意 (i in [2,n]),都有 (mid_{i-1} leqslant mid_{i})

    那么就可以用一个变量 (p) 来维护 (mid),从 (1) 开始不断地向后移动。

    但有可能 (mid[i-1]) 并非是以 (a[i]) 开头的最优解,继续考虑对每个 (i) 求出最大的 (mid)

    分开处理合法序列的左右两边,当 (i) 固定时,如果只看左边是否合法的话,那么从第一个不合法的位置开始,后面的都不合法(这不是理所当然的嘛),所以直接从 (mid_{i-1}) 开始向后暴力移动 (p)(也可以二分,但不便于后面的证明),扫到不合法的位置时就结束。此时在 ([mid_{i-1},p]) 中任取一个位置作为 (mid_{i}) 都可以满足序列左边合法,现在开始处理右边。

    右边对于 (p) 的移动是不具有单调性的,那么就暴力往回移动 (p),找到第一个使得右边序列合法的位置,此时 (p) 停留的位置必定是 (mid_{i}) 的最优值。

    暴力,暴力,全都是暴力。对于每次 (i) 都要把 (p) 向后移动若干位置再移回来,时间复杂度似乎为 (O(n^2)),但实际上是线性的,可以几十 (ms) 轻松跑过((n) 方过百万)。

    【时间复杂度证明】

    对于每个 (i),设 (p)(mid_{i-1}) 开始向后移动了 (x_{i}),又从 (mid_{i-1}+x_{i}) 开始向前移回去了 (y_{i}),那么总时间复杂度可以表示为 (Theta=sum_{i=1}^{n} (x_{i}+y_{i})) —— ①。

    对于每个 (i)(p)(mid_{i-1}) 开始移动了 (x_{i}-y_{i}) 后到达了 (mid_{i}),那么 (mid_{i}) ((i in [1,n])) 的总移动距离就可以表示为 (sum_{i=1}^{n} (x_{i}-y_{i}))

    又因为 (mid_{i}) 具有决策单调性,必定是从 (1) 移到 (n),所以总移动距离应为 (n),即:(n=sum_{i=1}^{n} (x_{i}-y_{i})) —— ②。

    由于序列 ([mid_{i-1},mid_{i-1}+x_{i}]) 中元素之和一定是小于等于 (S) 的,那么取其中点 (M(mid_{i-1}+frac{x_{i}}{2})),一定可以使得 (M) 两边都合法,即 (mid_{i} geqslant M),于是有 (mid_{i-1}+x_{i}-y_{i} geqslant mid_{i-1}+frac{x_{i}}{2}),即 (y_{i} leqslant frac{x_{i}}{2}) —— ③。

    由②③可知:

    (n=sum_{i=1}^{n} (x_{i}-y_{i}) geqslant sum_{i=1}^{n} frac{x_{i}}{2}),即 (sum_{i=1}^{n} frac{3}{2}x_{i} leqslant 3n)

    由①③可知:

    (Theta=sum_{i=1}^{n} (x_{i}+y_{i}) leqslant sum_{i=1}^{n} frac{3}{2}x_{i})

    于是有 (Theta leqslant 3n)

    时间复杂度得证,为 (O(n))

    (这样看来,向后移时的二分貌似都没必要写了)

    另外,有个 ( ext{julao}) 认为上述证明有问题,但具体她又说不清(这不是在扯淡么),如有不严谨处欢迎指出。

    【Code】

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #define LL long long
    #define Re register int
    using namespace std;
    const int N=1e5+5;
    int n,s,a[N];LL S[N];
    inline void in(Re &x){
        int f=0;x=0;char c=getchar();
        while(c<'0'||c>'9')f|=c=='-',c=getchar();
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x=f?-x:x;
    }
    inline int judge1(Re i,Re mid){return S[mid]-S[i-1]<=s;}
    //judge1()判断序列前半段
    inline int judge2(Re i,Re mid){return S[(mid<<1)-i+1]-S[mid]<=s;}
    //judge2()判断序列前半段
    int main(){
    //  freopen("b.in","r",stdin);
    //  freopen("b.out","w",stdout);
        in(n),in(s);
        for(Re i=1;i<=n;++i)in(a[i]),S[i]=S[i-1]+a[i];
        Re p=0;S[n+1]=S[n+2]=1e18;//为防止玄学错误,先把最后面的覆盖一下
        while((p+1<<1)<=n&&judge1(1,p+1))++p;//预处理出第一个mid
        while(p&&!judge2(1,p))--p;
        printf("%d
    ",(p<<1));
        for(Re i=2;i<=n;++i){
    //      if(p<i-1)p=i-1;//这句可加可不加
            while((p+1<<1)-i+1<=n&&judge1(i,p+1))++p;//向后移时注意判断右边界不能超过n
            while(p>=i&&!judge2(i,p))--p;//向前移回去,找到最大的合法mid_i
            printf("%d
    ",(p-i+1)<<1);//输出为长度
        }
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
    
  • 相关阅读:
    J2EE学习笔记:Filter
    J2EE学习笔记:HTTP协议
    J2EE学习笔记:JSP
    Hibernate 笔记(二) 数据关系
    top命令总结
    让gdb能打印C++中的容器类型
    ps命令注意事项
    自己动手写一个自动登录脚本gg
    request 中url拼接排序参数与签名算法
    python3.7 AES.MODE_ECB(128位) pkcs5padding 加密算法
  • 原文地址:https://www.cnblogs.com/Xing-Ling/p/11687610.html
Copyright © 2011-2022 走看看