BZOJ [P2124] 等差子序列

线段树维护哈希值

要求出现长度大于三的等差子序列,我们只要找到长度等于三的就可以了
初看本题没有思路,只能暴力枚举,O(n^4)
后来发现,这个序列是n的一个排列,那么每个数字都只会出现一次
我们可以维护一个 \(01\) 序列 B ,表示某个数字是否出现过,
然后我们从左往右枚举等差中项x并将该项在B中置为1,存在等差数列当且仅当,
B序列以x为中心的极大子区间不是回文子区间
我们该如何高效的判断回文子区间呢,首先维护B的正反两个序列
然后有两种做法
1.线段树维护 \(01\) 序列的哈希值,要注意预处理,以及具体在某步中移多少位
2.用bitset维护

线段树维护哈希值,64位自然溢出

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#define lson l, mid, rt<<1
#define rson mid + 1, r, rt<<1|1
#define ll unsigned long long
using namespace std;
const int MAXN = 10005, base = 233;
int init() {
    int rv = 0, fh = 1;
    char c = getchar ();
    while(c < '0' || c > '9') {
        if(c == '-') fh = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        rv = (rv<<1) + (rv<<3) + c - '0';
        c = getchar();
    }
    return fh * rv;
}
int T, n;
ll hash1[MAXN<<2], hash2[MAXN<<2], idx[MAXN<<2];
ll Query1(int L, int R, int l, int r,int rt) {
    if(L > R) return 0;
    if(L <= l && r <= R) {
        return hash1[rt];
    }
    int mid = (l + r) >>1;
    ll ans = 0;
    if(L <= mid) ans = Query1(L, R, lson);
    if(mid < R) {
        ans *= idx[min(R, r) - mid]; //注意min(R,r)
        ans += Query1(L, R, rson);
    }
    return ans;
}
ll Query2(int L, int R, int l, int r, int rt) {
    if(L > R) return 0;
    if(L <= l && r <= R) {
        return hash2[rt];
    }
    int mid = (l + r) >>1;
    ll ans = 0;
    if(mid < R) ans = Query2(L ,R, rson);
    if(L <= mid){
        ans *= idx[mid - max(L, l) + 1];
        ans += Query2(L, R, lson);
    }
    return ans;
}
void PushUp(int rt, int m) {
    hash1[rt] = hash1[rt<<1] * idx[m>>1] + hash1[rt<<1|1];
    hash2[rt] = hash2[rt<<1|1] * idx[m - (m>>1)] + hash2[rt<<1];
}
void Update(int x, int l, int r, int rt) {
    if(l >= r) {
        hash1[rt] = hash2[rt] = 1;
        return;
    }
    int mid = (l + r) >>1;
    if(x <= mid) Update(x, lson);
    else Update(x, rson);
    PushUp(rt, r - l + 1);
}
int main() {
    freopen("in.txt", "r", stdin);
    T = init();
    idx[0] = 1;
    for(int i = 1 ; i <= MAXN ; i++) {
        idx[i] = idx[i-1] * base;
    }
    while(T--) {
        n = init();
        memset(hash1, 0, sizeof(hash1));
        memset(hash2, 0, sizeof(hash2));
        bool f = 0;
        for(int i = 1 ; i <= n ; i++) {
            int x = init();
            int len = min(x - 1, n - x);
            if((!f) && (Query1(x - len, x - 1, 1, n, 1) != Query2(x + 1, x + len, 1, n, 1))) {
                f = 1;
            }
            Update(x, 1, n, 1);
        }
        printf("%c\n", f?'Y':'N');
    }
    fclose(stdin);
    return 0;
}

原文地址:https://www.cnblogs.com/Mr-WolframsMgcBox/p/8452817.html

时间: 2024-11-02 22:01:07

BZOJ [P2124] 等差子序列的相关文章

BZOJ 2124等差子序列 线段树&amp;&amp;hash

[题目描述 Description] 给一个 1 到 N 的排列{Ai},询问是否存在 1<=p1<p2<p3<p4<p5<…<pLen<=N(Len>=3),使得 Ap1,Ap2,Ap3,…ApLen 是一个等差序列. [输入描述 Input Description] 输入的第一行包含一个整数 T,表示组数. 下接 T 组数据,每组第一行一个整数 N,每组第二行为一个 1 到 N 的排列, 数字两两之间用空格隔开. [输出描述 Output Desc

BZOJ 2124: 等差子序列

Sol 线段树+Hash. 首先暴力 等差子序列至少3项就可以了,就枚举中项,枚举公差就可以了,只需要一个数在中项前出现,另一个数在中项前没出现过就可以了.复杂度 \(O(n^2)\) 然后我想了一个虽然复杂度没变(因为我不会设计这个数据结构...) 但是好像有点用的算法,就是枚举中项,考虑从一个中项转移到另一个中项,那就是 \(\pm \Delta\) 就可以了...如果能够用数据结构维护这个操作,那就灰常好了.变换中项也就是变换折叠的位置吧. 标算呢...就是用线段树维护Hash,一个数字出

BZOJ 2124: 等差子序列 线段树维护hash

2124: 等差子序列 Description 给一个1到N的排列{Ai},询问是否存在1<=p1=3),使得Ap1,Ap2,Ap3,…ApLen是一个等差序列. Input 输入的第一行包含一个整数T,表示组数.下接T组数据,每组第一行一个整数N,每组第二行为一个1到N的排列,数字两两之间用空格隔开. Output 对于每组数据,如果存在一个等差子序列,则输出一行“Y”,否则输出一行“N”. Sample Input 2 3 1 3 2 3 3 2 1 Sample Output N Y HI

bzoj 2124 等差子序列 树状数组维护hash+回文串

等差子序列 Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 1919  Solved: 713[Submit][Status][Discuss] Description 给一个1到N的排列{Ai},询问是否存在1<=p1<p2<p3<p4<p5<…<pLen<=N (Len>=3), 使得Ap1,Ap2,Ap3,…ApLen是一个等差序列. Input 输入的第一行包含一个整数T,表示组数. 下接T组数据,

2124: 等差子序列 - BZOJ

Description 给一个1到N的排列{Ai},询问是否存在1<=p1=3),使得Ap1,Ap2,Ap3,-ApLen是一个等差序列. Input 输入的第一行包含一个整数T,表示组数.下接T组数据,每组第一行一个整数N,每组第二行为一个1到N的排列,数字两两之间用空格隔开. Output 对于每组数据,如果存在一个等差子序列,则输出一行"Y",否则输出一行"N". Sample Input 2 3 1 3 2 3 3 2 1 Sample Output

Bzoj2124 等差子序列

Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 911  Solved: 337 Description 给一个1到N的排列{Ai},询问是否存在1<=p1=3),使得Ap1,Ap2,Ap3,…ApLen是一个等差序列. Input 输入的第一行包含一个整数T,表示组数.下接T组数据,每组第一行一个整数N,每组第二行为一个1到N的排列,数字两两之间用空格隔开. Output 对于每组数据,如果存在一个等差子序列,则输出一行“Y”,否则输出一行“N”.

Codevs 1283 等差子序列

1283 等差子序列 2010年 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master 题解 题目描述 Description 给一个 1 到 N 的排列{Ai},询问是否存在 1<=p1<p2<p3<p4<p5<…<pLen<=N(Len>=3),使得 Ap1,Ap2,Ap3,…ApLen 是一个等差序列. 输入描述 Input Description 输入的第一行包含一个整数 T,表示组数. 下接 T 组数据,每组第

[bzoj2124]等差子序列(hash+树状数组)

我又来更博啦 2124: 等差子序列 Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 941  Solved: 348[Submit][Status][Discuss] Description 给一个1到N的排列{Ai},询问是否存在1<=p1=3),使得Ap1,Ap2,Ap3,…ApLen是一个等差序列. Input 输入的第一行包含一个整数T,表示组数.下接T组数据,每组第一行一个整数N,每组第二行为一个1到N的排列,数字两两之间用空格隔开. O

bzoj2124 等差子序列(hash+线段树)

2124: 等差子序列 Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 719  Solved: 261[Submit][Status][Discuss] Description 给一个1到N的排列{Ai},询问是否存在1<=p1=3),使得Ap1,Ap2,Ap3,…ApLen是一个等差序列. Input 输入的第一行包含一个整数T,表示组数.下接T组数据,每组第一行一个整数N,每组第二行为一个1到N的排列,数字两两之间用空格隔开. Output 对