bzoj千題計劃312:bzoj2119: 股市的預測(後綴數組+st表)

https://www.lydsy.com/JudgeOnline/problem.php?id=2119php

 

題意:將給定數組差分後,求ABA形式的字串個數,要求|B|=m,|A|>0ios

 

一、後綴數組求出 差分序列 和 翻轉差分序列後的序列 的sa,rk,heightgit

二、枚舉len=|A|,對差分序列每len個分一塊,記每一塊的關鍵點位塊內第一個元素數組

三、枚舉每個關鍵點i,令j=i+len+m,求出若i做爲A的最後一個元素,向左能延伸最遠點x,若i做爲A的第一個元素,向右能延伸的最遠點yspa

  那麼i取[x,y]內的任意長爲len的一塊均可以最爲A,因此答案累加 y-x+1 - len +1rest

四、爲避免重複,限制向左向右最長延伸長度爲len-1,即每一個A只能佔據一個關鍵點code

五、向左能延伸的最遠點就是 分別以i、j結尾的最長公共後綴,即求[1,i]和[1,j]的最長公共後綴,轉化成求翻轉序列的最長公共前綴blog

      向右能延伸的最遠點就是 分別以i、j開始的最長公共前綴,即求[i,n]和[j,n]的最長公共前綴get

      這能夠用後綴數組完成string

 

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

#define N 50001
#define M 15

typedef long long LL;

int n,m,tot;
int b[N];

int a1[N],a2[N];

int has[N];

int sa1[2][N],rk1[2][N],h1[N];
int sa2[2][N],rk2[2][N],h2[N];

int p1,q1=1;
int p2,q2=1;
int v[N];
int k;

int st1[N][M+1],st2[N][M+1];

void read(int &x)
{
    x=0; int f=1; char c=getchar();
    while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); }
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    x*=f;
}

void mul(int *sa,int *rk,int*SA,int *RK)
{
    for(int i=1;i<=n;++i) v[rk[sa[i]]]=i;
    for(int i=n;i;--i) if(sa[i]>k) SA[v[rk[sa[i]-k]]--]=sa[i]-k;
    for(int i=n-k+1;i<=n;++i) SA[v[rk[i]]--]=i;
    for(int i=1;i<=n;++i) RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i]]!=rk[SA[i-1]] || rk[SA[i]+k]!=rk[SA[i-1]+k]);
}

void presa(int &p,int &q,int a[N],int sa[2][N],int rk[2][N])
{
    memset(v,0,sizeof(v));
    for(int i=1;i<=n;++i) v[a[i]]++;
    for(int i=1;i<=tot;++i) v[i]+=v[i-1];
    for(int i=1;i<=n;++i) sa[p][v[a[i]]--]=i;
    for(int i=1;i<=n;++i) rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(a[sa[p][i]]!=a[sa[p][i-1]]);
    for(k=1;k<n;k<<=1,swap(p,q)) 
    mul(sa[p],rk[p],sa[q],rk[q]);
}

void get_height(int *a,int *h,int *sa,int *rk)
{
    int k=0,j;
    for(int i=1;i<=n;++i)
    {
        j=sa[rk[i]-1];
        while(a[i+k]==a[j+k]) 
        k++;
        h[rk[i]]=k;
        if(k) k--;
    }
}

void prest(int h[N],int st[N][M+1])
{
    for(int i=2;i<=n;++i) st[i][0]=h[i];
    for(int i=1,k=2;i<=M;++i,k<<=1)
        for(int j=2;j+k-1<=n;++j)
            st[j][i]=min(st[j][i-1],st[j+k/2][i-1]);
}

int get(int st[N][M+1],int i,int j,int *rk)
{
    i=rk[i]; j=rk[j];
    if(i>j) swap(i,j);
    i++;
    int l=1.0*log(j-i+1)/log(2);
    return min(st[i][l],st[j-(1<<l)+1][l]);
}

void solve()
{
    LL ans=0;
    int j;
    int lcp,lcs,sum;
    for(int len=1;len<n;++len)
        for(int i=1;i+len+m<=n;i+=len)
        {
            j=i+len+m;
            lcs=get(st1,i,j,rk1[p1]);
            if(lcs>len) lcs=len;
            lcp=get(st2,n-j+1,n-i+1,rk2[p2]);
            if(lcp>len) lcp=len;
            sum=lcp+lcs-1;
            if(sum>=len) 
            {
                ans+=sum-len+1;
            //    printf("%d %d %d %d\n",i,j,len,sum-len+1);
            }
        }
    cout<<ans;
}

int main()
{
    freopen("nt2011_stock.in","r",stdin);
    freopen("nt2011_stock.out","w",stdout); 
    read(n); read(m);
    for(int i=1;i<=n;++i) read(b[i]);
    for(int i=1;i<n;++i) a1[i]=b[i+1]-b[i],has[i]=a1[i];
    n--;
    sort(has+1,has+n+1);
    tot=unique(has+1,has+n+1)-has-1;
    for(int i=1;i<=n;++i) a1[i]=lower_bound(has+1,has+tot+1,a1[i])-has;
    for(int i=1;i<=n;++i) a2[n-i+1]=a1[i];
    presa(p1,q1,a1,sa1,rk1);
    get_height(a1,h1,sa1[p1],rk1[p1]);
    presa(p2,q2,a2,sa2,rk2);
    get_height(a2,h2,sa2[p2],rk2[p2]);
    prest(h1,st1);
    prest(h2,st2);
    solve();
}
相關文章
相關標籤/搜索