[BZOJ2124]等差子序列/[CF452F]Permutation

[BZOJ2124]等差子序列/[CF452F]Permutation

题目大意:

一个\(1\sim n\)的排列\(A_{1\sim n}\),询问是否存在\(i,j(i<j)\),使得\(A_i<A_j\)\(\frac{A_i+A_j}2\)\(i,j\)之间出现。

BZOJ上的数据范围:\(n\le10000\);
CF上的数据范围:\(n\le3\times10^5\)

思路:

从左到右枚举每一个数,用两个布尔数组\(b_0,b_1\)分别维护数值为\(i\)的数是否在当前数的左边、右边出现。然后将与当前数差值相等的位置对应起来(如,当前\(A_i=3\)时,将\(b_{0,1}\)\(b_{1,5}\)对应起来),看一下对应位置有没有都是\(1\)的,如果有,则说明存在。

使用bitset优化可以做到\(\mathcal O(\frac{n^2}{32})\),但还是过不了。

发现如果只用一个数组\(b\)维护左边出现过的数,那么对于当前位置\(i\),若以\(b_{A_i}\)为中心的极大字符串是不是回文串,说明一个在左边出现,一个在右边出现,那么一定存在解。而确定中心的回文串判定可以用树状数组维护哈希实现。

事件复杂度\(\mathcal O(n\log n)\)

源代码:

#include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
const int N=300001;
const unsigned base=13;
unsigned pwr[N];
int n;
class FenwickTree {
    private:
        unsigned val[N];
        int lowbit(const int &x) const {
            return x&-x;
        }
        unsigned query(const int &p) const {
            unsigned ret=0;
            for(register int i=p;i;i-=lowbit(i)) {
                ret+=val[i]*pwr[p-i];
            }
            return ret;
        }
    public:
        void modify(const int &p) {
            for(register int i=p;i<=n;i+=lowbit(i)) {
                val[i]+=pwr[i-p];
            }
        }
        unsigned query(const int &l,const int &r) const {
            return query(r)-query(l-1)*pwr[r-l+1];
        }
};
FenwickTree t[2];
int main() {
    n=getint();
    for(register int i=pwr[0]=1;i<=n;i++) {
        pwr[i]=pwr[i-1]*base;
    }
    bool ans=false;
    for(register int i=1;i<=n;i++) {
        const int x=getint();
        const int len=std::min(x-1,n-x);
        ans|=t[0].query(x-len,x-1)!=t[1].query(n-x-len+1,n-x);
        t[0].modify(x);
        t[1].modify(n-x+1);
    }
    puts(ans?"YES":"NO");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/skylee03/p/9638702.html