[bzoj2124][哈希]等差子序列

2124: 等差子序列

Time Limit: 3 Sec Memory Limit: 259 MB
Submit: 1854 Solved: 689
[Submit][Status][Discuss]
Description

给一个1到N的排列{Ai},询问是否存在1<=p1

sol:

第一眼看上去就是2018芜湖nbc出的那题对吧,但是我没改那天的题。所以看到这题又不会做了。看了一眼题解就迅速的回忆起来了。
一个暴力就是对于出现在当前的中点左边的权值设为1,然后扫一下左边看一下右边能不能匹配上。
那么如果中点的权值为x,那么权值的那个桶实际上总是一个回文的,因为x+N,x-N全是0,或者全是1。所以我们用一个线段树来维护正反的hash值,看一下是不是回文串即可。

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cmath>
using namespace std;
typedef long long ll;

int n,m;

inline int read()
{
    char c;
    bool pd=0;
    while((c=getchar())>'9'||c<'0')
    if(c=='-') pd=1;
    int res=c-'0';
    while((c=getchar())>='0'&&c<='9')
    res=(res<<3)+(res<<1)+c-'0';
    return pd?-res:res;
}
const int N=11000;
const int M=41000;
const int pyz=1e9+7;
const int base=10;
int a[N];
int val[M][2],Pow[N];
inline void tag_down(int k,int l,int r)
{
    int mid=l+r>>1;
    if(val[k][0])
    {
        val[k<<1][0]=(val[k<<1][0]+val[k][0])%pyz;
        val[k<<1|1][0]=(val[k<<1|1][0]+(ll)val[k][0]*Pow[mid+1-l]%pyz)%pyz;
        val[k][0]=0;
    }
    if(val[k][1])
    {
        val[k<<1|1][1]=(val[k<<1|1][1]+val[k][1])%pyz;
        val[k<<1][1]=(val[k<<1][1]+(ll)val[k][1]*Pow[r-mid]%pyz)%pyz;
        val[k][1]=0;
    }
}
inline int query(int k,int l,int r,int x,int y)
{
    if(l==r) return val[k][y];
    int mid=l+r>>1;
    tag_down(k,l,r);
    if(mid>=x) return query(k<<1,l,mid,x,y);
    return query(k<<1|1,mid+1,r,x,y);
}
inline void modify0(int k,int l,int r,int x)
{
    if(l>=x)
    {
        val[k][0]=(val[k][0]+Pow[l-x])%pyz;
        return;
    }
    int mid=l+r>>1;
    tag_down(k,l,r);
    if(mid>=x) modify0(k<<1,l,mid,x);
    modify0(k<<1|1,mid+1,r,x);
}
inline void modify1(int k,int l,int r,int x)
{
    if(r<=x)
    {
        val[k][1]=(val[k][1]+Pow[x-r])%pyz;
        return;
    }
    int mid=l+r>>1;
    tag_down(k,l,r); 
    modify1(k<<1,l,mid,x);
    if(mid+1<=x) modify1(k<<1|1,mid+1,r,x);
}

inline void modify(int x)
{
    modify0(1,1,n,x);
    modify1(1,1,n,x); 
}
inline int query(int x)
{
    int a,b;
    if(n-x+1>=x)
    {
        b=(query(1,1,n,1,1)-(ll)query(1,1,n,x,1)*Pow[x-1]%pyz+pyz)%pyz;
        a=(query(1,1,n,x+x-1,0)-(ll)query(1,1,n,x,0)*Pow[x-1]%pyz+pyz)%pyz;
        return a==b;
    }
    else
    {
        a=(query(1,1,n,n,0)-(ll)query(1,1,n,x,0)*Pow[n-x]%pyz+pyz)%pyz;
        b=(query(1,1,n,x-(n-x),1)-(ll)query(1,1,n,x,1)*Pow[n-x]%pyz+pyz)%pyz;
        return a==b;
    }
}
inline void solve()
{
    n=read();
    memset(val,0,sizeof(val));
    for(int i=1;i<=n;++i) a[i]=read();
    for(int i=1;i<=n;++i)
    {
        if(!query(a[i]))
        {
            printf("Y\n");
            return;
        }
        modify(a[i]);
//      cout<<query(1,1,n,1,1);
    }
    printf("N\n");
}
int main()
{
//  freopen("2124.in","r",stdin);
//  freopen("2124.out","w",stdout);
    Pow[0]=1;
    for(int i=1;i<=10000;++i) Pow[i]=(ll)Pow[i-1]*base%pyz;
    int T=read();
    while(T--) solve();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值