• P2757 [国家集训队]等差子序列


    题目链接

    https://www.luogu.com.cn/problem/P2757

    题目大意

    给你一个 1 ~ N 的排列,问是否存在等差子序列

    解题思路

    权值线段树 + hash

    首先要满足等差序列的条件为 a[ i ] + a[ k ] = 2 * a[ j ] ,其中 i < j < k

    那么根据这个条件我们就可以枚举等差序列中心,判断两端是否有满足条件的 a[i] , a[k]

    我们可以知道若一个排列长度为 3 , 并且我们要以 2 为等差序列中心 , 那么 1 3 就必须在 2 的两端

    理解以上后,我们可以选择枚举等差序列的中心 j ,来找它的两端是否有满足条件的 i , k 

    假设现在有个数组 vis , 其中 vis[i] 表示 i 这个数是否已经出现

    举个栗子 , 假设现在序列为 1 2 3 , 那么我们枚举到 a[1] 时vis[1] = 1 , vis[2] = 0 , vis[3] = 0

    当我们枚举到 a[2] 时 , vis[2] = 1 , vis[1] = 1 , vis[3] = 0,枚举到 a[3] 的时全都等于1

    其中,枚举到 a[2] 即枚举到 2 这个数的时候 , vis[1] = 1 , vis[3] = 0 , 数组呈现为 110 

    也就是说 1 这个数是在 2 之前出现的 , 3这个数是在 2 之后出现的,那么我们就可以以

    a[2] 为中心构造等差子序列;而如果枚举到2时 1、3 都在2的同一端即 111 或者 010

    那么就无法以a[2]为中心构造等差子序列

    根据以上我们会发现当以 X 这个数为中心时,如果两端对称位置数的数组值相同

    则说明这对称位置的数同时存在于 X 的同一侧,也就是它们和 X 无法构成等差子序列

    那如果对称位置数组值不相同,则它们存在 X 的不同侧,也就是它们可以和 X 构成等差子序列

    那么倘若 X 两端对称位置数的数组值全相同,则以 X 为中心的数组呈现会是一个回文串(左右两端相同)

    所以我们只要枚举每个数,每次枚举判断这个数作为中心是否会产生回文串 , 待找到不回文或者枚举结束即可

    至于回文我们可以用线段树来维护正反hash值来操作

    AC_Coder

    #include<bits/stdc++.h>
    #define rep(i,a,n) for (int i=a;i<=n;i++)
    #define per(i,n,a) for (int i=n;i>=a;i--)
    #define int long long
    #define ll long long
    #define ull unsigned long long
    using namespace std;
    const int P = 13331 , mod = 999998639; 
    const int N = 2e5 + 10;
    ull power[N];
    int a[N];
    struct Seg_ment{
        int l , r ;
        ull pre , suf;
    }tree[N << 2];
    void push_up(int id , int len1 , int len2)
    {
        tree[id].pre = tree[id << 1].pre * power[len2] + tree[id << 1 | 1].pre;
        tree[id].pre %= mod;
        tree[id].suf = tree[id << 1 | 1].suf * power[len1] + tree[id << 1].suf;
        tree[id].suf %= mod;
    }
    void build(int id , int l , int r)
    {
        tree[id].pre = tree[id].suf = 0; 
        tree[id].l = l , tree[id].r = r;
        if(l == r) return ;
        int mid = l + r >> 1;
        build(id << 1 , l , mid);
        build(id << 1 | 1 , mid + 1 , r);
        push_up(id , mid - tree[id].l + 1 , tree[id].r - mid);
    }
    void update(int id , int pos , int val)
    {
        if(tree[id].l == tree[id].r)
        {
            tree[id].pre = tree[id].suf = val;
            return ;
        }
        int mid = tree[id].l + tree[id].r >> 1;
        if(pos <= mid) update(id << 1 , pos , val);
        else update(id << 1 | 1 , pos , val);
        push_up(id , mid - tree[id].l + 1 , tree[id].r - mid);
    }
    ull query_range(int id , int l , int r , int ch)
    {
        if(tree[id].l >= l && tree[id].r <= r)
        {
            if(ch == 1) return tree[id].pre ;
            return tree[id].suf;
        }
        int mid = tree[id].l + tree[id].r >> 1;
        if(r <= mid) return query_range(id << 1 , l , r , ch);
        if(l > mid) return query_range(id << 1 | 1 , l , r , ch);
        ull lson = query_range(id << 1 , l , r , ch);
        ull rson = query_range(id << 1 | 1 , l , r , ch);
        ull ans ;
        if(ch == 1) ans = lson * power[min(r , tree[id].r) - mid] + rson;
        else ans = rson * power[mid - max(tree[id].l , l) + 1] + lson;
        return ans % mod;
    }
    void init()
    {
        power[0] = 1;
        rep(i , 1 , 100000)
        power[i] = power[i - 1] * P % mod;
    }
    signed main()
    {
        init();
        int t;
        cin >> t;
        while(t --)
        {
            int n , flag = 0 , x; 
            cin >> n;
            build(1 , 1 , n);
            rep(i , 1 , n)
            {
                cin >> x;
                update(1 , x , 1);
                if(i == 1 || i == n) continue ;
                int len = min(x , n - x + 1);
                int y = query_range(1 , x - len + 1 , x , 1);
                int z = query_range(1 , x , x + len - 1 , 2);
                if(y != z)    flag = 1 ;
            }
            if(flag) cout << "Y
    ";
            else cout << "N
    ";
        }
        return 0;
    }
    凡所不能将我击倒的,都将使我更加强大
  • 相关阅读:
    Python学习笔记:pandas.read_csv分块读取大文件(chunksize、iterator=True)
    Python学习笔记:os.stat().st_size、os.path.getsize()获取文件大小
    7-1 打印沙漏
    7-1 币值转换
    7-1 抓老鼠啊~亏了还是赚了?
    第四周编程总结哦也
    2018秋寒假作业6—PTA编程总结3
    PTA编程总结3
    PTA编程总结1
    秋季学期学习总结
  • 原文地址:https://www.cnblogs.com/StarRoadTang/p/13026410.html
Copyright © 2020-2023  润新知