bzoj thousand questions plan 317: bzoj4650: [Noi2016] Excellent split (suffix array + difference)

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

 

If it can be preprocessed

suf[i] The number of substrings in the form of AA ending in i

pre[i] The number of substrings in the form of AA starting with i

ans= ∑ suf[i]*pre[i+1]

The method of finding these two arrays is similar to bzoj 2119, 3238

Enumerate the length len of |A|, divide the sequence into blocks every len, and take the first element in each block as the key point

Every legal AA occupies exactly two key points

Enumerate each key point i, take j=i+len

Calculate the lcp of [i,n] and [j,n], and the lcs of [1,i] and [1,j] (via the suffix array of original and reverse strings)

Assuming that i is the benchmark, the farthest point of lcp's backward matching is r, and the farthest point of lcs' forward matching is l

Let cnt=r-l+1 - len + 1

Then the beginning of AA can be a substring with any length of len in [l, r]. There are cnt substrings, that is, pre[l,l+cnt-1] will add a contribution

Assuming that j is the benchmark, the farthest point of lcp's backward matching is r, and the farthest point of lcs' forward matching is l

Let cnt=r-l+1 - len + 1

Then the end of AA can be a substring of any length of len in [l, r]. There are cnt substrings, that is, pre[r,r-cnt+1] will add a contribution

Cumulative Contribution Using Differences

 

Notice:

When using a suffix array, when there are multiple sets of data, in addition to the v array used for statistics, the rank array should also be cleared.

The following +k causes the rank to use the rank exceeding n, and the rank exceeding n is stored when the rank of the previous set of data is stored.

    

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

#define N 30002

using namespace std;

int n;
char s[N];

int pre[N],suf[N];

int Log[N];

struct SA
{
    int a[N];
    int sa[2][N],rk[2][N];
    int v[N];
    int p,q;
    int k;
    int height[N];
    int st[N][15];

    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 pre_sa ()
    {
        p = 0 ; q = 1
        memset(v,0,sizeof(v));
        memset(rk,0,sizeof(rk));
        for(int i=1;i<=n;++i) v[a[i]]++;
        for(int i=1;i<=26;++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 pre_height()
    {
        int j,k=0;
        for(int i=1;i<=n;++i)
        {
            j=sa[p][rk[p][i]-1];
            while(a[i+k]==a[j+k]) k++;
            height[rk[p][i]]=k;
            if(k) k--;
        }
    }    

    void pre_st()
    {
        memset(st,0,sizeof(st));
        for(int i=2;i<=n;++i) st[i][0]=height[i];
        for(int j=1,k=1;j<=14;++j,k<<=1)
            for(int i=2;i+k*2-1<=n;++i)
                st[i][j]=min(st[i][j-1],st[i+k][j-1]);
    }

    void pre()
    {
        pre_sa ();
        pre_height();
        pre_st();
    }

    int get(int i,int j)
    {
        i=rk[p][i]; j=rk[p][j];
        if(i>j) swap(i,j);
        i++;
        int l=Log[j-i+1];
        return min(st[i][l],st[j-(1<<l)+1][l]);    
    }    
};
SA SA1, SA2;

void solve()
{
    memset(pre,0,sizeof(pre));
    memset(suf,0,sizeof(suf));
    int j;
    int lcp,lcs;
    int cnt=0;
    for(int len=1;len<n;++len)
    {
         for ( int i = len; i + len <= n; i + = len)
        {
            j = i + len;
            lcp=SA1.get(i,j);
            if(lcp>len) lcp=len;
            lcs=SA2.get(n-i+1,n-j+1);
            if(lcs>len) lcs=len;
            if(lcp+lcs-1>=len)
            {
                suf[j+len-lcs]++;
                suf[j+lcp]--;
                pre[i-lcs+1]++;
                for [i + lcp-len + 1 ] - ;
            }
        }
    }
    for(int i=2;i<=n;++i) pre[i]+=pre[i-1],suf[i]+=suf[i-1];
    long long ans=0;
    for(int i=2;i<=n-2;++i) ans+=1LL*suf[i]*pre[i+1];
    cout<<ans<<'\n';
}

intmain ()
{
    //freopen("testdata.in","r",stdin); 
    //freopen("__.txt","w",stdout);
    int T;
    scanf("%d",&T);
    for(int i=2;i<N;++i) Log[i]=Log[i>>1]+1;
    while(T--)
    {
        scanf("%s",s+1);
        n=strlen(s+1);
        for(int i=1;i<=n;++i) SA1.a[i]=s[i]-'a'+1;
        memcpy(SA2.a,SA1.a,sizeof(SA2.a));
        reverse(SA2.a+1,SA2.a+n+1);
        SA1.a [n + 1 ] = SA2.a [n + 1 ] = 0 ;
        SA1.pre ();
        SA2.pre ();
        solve();
    }
}

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325260230&siteId=291194637