【HAOI2016]同じ文字を見つけるために、(接尾辞配列スタック単調+)

【HAOI2016]同じ文字を見つけるために、(接尾辞配列スタック単調+)

フェイス質問

このような同じシーケンス番号二つのサブプログラム、その文字列内の2点の抽出部分文字列で得られた二つの文字列、それぞれが与えられ。場合にのみ異なる位置に2つのサブ文字列の場合、2つの異なるソリューションを提供しています。

分析

私たちは2つの文字列を、セパレータの真ん中。(\ \テキスト{AABB} \ ) と\(\テキスト{BBAAは} \ ) となる({|鳥類およびBBAAテキストAABB} \ \)\私たちは、次のような二つの同一の文字列を、考える\(\テキストBB} {\) 二つの新しいサフィックス文字列に対応\(BB | BBAA \)\(\テキスト鳥やBBAAを} {\)。LCPを簡単に私たちは、このように撤回元の2つの文字から、二つのサブ文字列を確保し、両方のLCP決して文字区切り終了を含め、見つかりました。

2つのサフィックスを列挙して、最小のLCPを得るために、ST-テーブルクエリを使用しています。しかし、この複雑であることができ、我々はそう(O(N ^ 2)\ \) 、最適化する必要があります。

接尾辞2 LCPが最小間隔に相当する高さである:任意の2つのサフィックスLCPの高さを利用して、時間の配列を追求するユニークな性質を考えます。つまり、ソート後、次に小さい長さLCPの接尾番号。このように、我々は、この最小単調性を維持するために、スタックを使用することができます。前者の2例を使用して文字列、Bサブストリングに先行するサブサブストリングは、回答のモノトーンを取得スタック

コード

(第1幕)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define maxn 400000
using namespace std;
typedef long long ll;
int n,m,tot;
char a[maxn+5],b[maxn+5],s[maxn+5];
 
void sort(int *ans,int *fi,int *se,int sz,int maxv){
    static int buck[maxn+5];
    for(int i=0;i<=maxv;i++) buck[i]=0;
    for(int i=1;i<=sz;i++) buck[fi[i]]++;
    for(int i=0;i<=maxv;i++) buck[i]+=buck[i-1];
    for(int i=sz;i>=1;i--) ans[buck[fi[se[i]]]--]=se[i]; 
} 
int sa[maxn+5];
int rk[maxn+5];
int height[maxn+5];
void suffix_sort(char *str,int n,int m){
    static int se[maxn+5];
    for(int i=1;i<=n;i++){
        rk[i]=str[i];
        se[i]=i;
    }
    sort(sa,rk,se,n,m);
    for(int k=1;k<=n;k*=2){
        int p=0;
        for(int i=n-k+1;i<=n;i++) se[++p]=i;
        for(int i=1;i<=n;i++){
            if(sa[i]>k) se[++p]=sa[i]-k;
        }
        sort(sa,rk,se,n,m);
        swap(se,rk);
        p=1; 
        rk[sa[1]]=1;
        for(int i=2;i<=n;i++){
            if(se[sa[i-1]]==se[sa[i]]&&se[sa[i-1]+k]==se[sa[i]+k]) rk[sa[i]]=p; 
            else rk[sa[i]]=++p; 
        }
        if(p==n) break;
        m=p;
    }   
} 
void get_height(char *str,int n,int m){
    suffix_sort(str,n,m);
    for(int i=1;i<=n;i++) rk[sa[i]]=i;
    int k=0;
    for(int i=1;i<=n;i++){
        if(k) k--;
        int j=sa[rk[i]-1];
        while(str[i+k]==str[j+k]) k++;
        height[rk[i]]=k;
    }
}

struct node{
    ll a;
    ll b;
    int h;
    node(){
        
    }
    node(ll _a,ll _b,int _h){
        a=_a;
        b=_b;
        h=_h;
    }
    friend bool operator < (node p,node q){
        return p.h<q.h;
    }
    friend node operator + (node p,node q){
        return node(p.a+q.a,p.b+q.b,p.h);
    }
};
int top=0;
node stk[maxn+5];

int main(){
    scanf("%s",a+1);
    scanf("%s",b+1);
    n=strlen(a+1),m=strlen(b+1);
    tot=0;
    for(int i=1;i<=n;i++) s[++tot]=a[i];
    s[++tot]='|';
    for(int i=1;i<=n;i++) s[++tot]=b[i];
    get_height(s,tot,128);
    ll ans=0;
    ll cnta=0,cntb=0;
    for(int i=2;i<=tot;i++){
        node now=node(0,0,height[i]);
        if(sa[i-1]<=n) now.a++;
        else if(sa[i-1]>n+1) now.b++; 
        while(top>0&&now<stk[top]){
            cnta-=stk[top].a*stk[top].h;
            cntb-=stk[top].b*stk[top].h;
            now=now+stk[top];
            top--;
        }
        stk[++top]=now;
        cnta+=now.a*now.h;
        cntb+=now.b*now.h;
        if(sa[i]<=n) ans+=cntb;
        else if(sa[i]>n+1) ans+=cnta;
    }
    printf("%lld\n",ans);
} 

おすすめ

転載: www.cnblogs.com/birchtree/p/12221299.html
おすすめ