bzoj 2124 等差子序列 (线段树维护hash)

2124: 等差子序列

Time Limit: 3 Sec  Memory Limit: 259 MB
Submit: 1922  Solved: 714
[Submit][Status][Discuss]

Description

给一个1到N的排列{Ai},询问是否存在1<=p1<p2<p3<p4<p5<…<pLen<=N (Len>=3),
使得Ap1,Ap2,Ap3,…ApLen是一个等差序列。
 

Input

输入的第一行包含一个整数T,表示组数。
下接T组数据,每组第一行一个整数N,每组第二行为一个1到N的排列,数字两两之间用空格隔开。
N<=10000,T<=7
 

Output

对于每组数据,如果存在一个等差子序列,则输出一行“Y”,否则输出一行“N”。
 

Sample Input

2
3
1 3 2
3
3 2 1

Sample Output

N
Y
 
思路:
 
线段树神仙操作。。完全想不到怎么用线段树写,看了别人题解看了一天才看懂这操作。。
题目要求存在个数不小于3的等差序列就行了,那么我们只要找到三个数可以组成等差序列就可以了。
我们先从1-n逐步插入,用01表示插入的状态吗如果插入了就标为1,然后只要找出当前值左右两边是否存在
距离相等但状态不同的点,如果有的话那么就存在这么一种等差序列,因为状态不同只有一种情况:一个之前
就已经插入了,一个还没插入,但另一个迟早会插入,所以我们不用管,只要找到这个就可以确定他是等差序列了。
用线段树维护一下hash就行了。
线段树维护的操作比较麻烦,主要就是将这个由01组成的序列由二进制转成10进制来保存,每一步都取下模,如果这
两个数的十进制不同,那他们的二进制肯定也不同。这样就可以判断出答案了。
 
实现代码;
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mid ll m = (l + r) >> 1
const ll M = 1e5+10;
const ll md = 1e9+7;
ll suml[M<<2],sumr[M<<2],a[M],pw[M];
void pushup(ll l,ll r,ll rt){
    ll len = r - l + 1;
    ll m = len / 2;
    suml[rt] = (suml[rt<<1]*pw[m]+suml[rt<<1|1])%md;
    sumr[rt] = (sumr[rt<<1|1]*pw[len-m]+sumr[rt<<1])%md;
    return ;
}

void update(ll p,ll l,ll r,ll rt){
    if(l == r){
        suml[rt] = sumr[rt] = 1;
        return ;
    }
    mid;
    if(p <= m) update(p,lson);
    else update(p,rson);
    pushup(l,r,rt);
}

ll queryl(ll L,ll R,ll l,ll r,ll rt){
    if(L > R) return 0;
    if(L == l&&R == r) return suml[rt];
    mid;
    if(L > m) return queryl(L,R,rson);
    else if(R <= m) return queryl(L,R,lson);
    else return (queryl(L,m,lson)*pw[R-m]+queryl(m+1,R,rson))%md;
}

ll queryr(ll L,ll R,ll l,ll r,ll rt){
    if(L > R) return 0;
    if(L == l&&R == r) return sumr[rt];
    mid;
    if(L > m) return queryr(L,R,rson);
    else if(R <= m) return queryr(L,R,lson);
    else  return (queryr(L,m,lson)+queryr(m+1,R,rson)*pw[m-L+1])%md;
}

int main()
{
    ll t,n;
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    cin>>t;
    pw[1] = 2;
    for(ll i = 2;i <= 100001;i++)
        pw[i] = (pw[i-1]*2)%md;
    while(t--){
        cin>>n;
        memset(suml,0,sizeof(suml));
        memset(sumr,0,sizeof(sumr));
        memset(a,0,sizeof(a));
        ll flag = 1;
        for(ll i = 1;i <= n;i ++) cin>>a[i];
        for(ll i = 1;i <= n;i ++){
            ll len = min(a[i]-1,n-a[i]);
            ll t1 = queryl(a[i]-len,a[i]-1,1,n,1);
            ll t2 = queryr(a[i]+1,a[i]+len,1,n,1);
            if(t1!=t2){
                flag = 0;break;
            }
            update(a[i],1,n,1);
        }
        if(!flag) cout<<"Y"<<endl;
        else cout<<"N"<<endl;
    }
}
原文地址:https://www.cnblogs.com/kls123/p/8849776.html