codeforces 123D 後綴數組

題意:

給你一個串,求所有不同字串的貢獻和,每種字串的貢獻,k*(k+1)/2,k爲該子串出現的次數

題解:

aaaa這個串中,a的貢獻是10,即4+3+2+1,第一個a的單獨貢獻爲4,第二個a的貢獻是3......每個串的貢獻就是跟他之後的子串以及自己匹配一次。記cnt爲到這一位的該子串個數,一開始爲0,ans爲貢獻和,到1:cnt+=1,ans+=cnt;到2:cnt+=1,ans+=cnt,跟之前所有出現過的子串作此匹配;到3:cnt+=1,ans+=cnt;到4:cnt+=1,ans+=cnt

一開始ans爲n*(n+1)/2,每個串自己跟自己匹配一次的次數,之後求解不用再算這部分。

每個串後面的串個數,可以用單調棧做一下,基本過程就參照aaaa這個串a子串的貢獻求解方法。

關於height數組的性質。在i,向左找到第一個j1使,height[j1]<height[i],向右找到第一個j2,

使height[j2]<height[i]。j2-j1-1的值等於長度爲height[i]的串出現了多少次。

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10,inf=0x3f3f3f3f;
int sa[N];
int rk[N];
int tmp[N];
int lcp[N];
char s[N];
int n,k;
bool cmp(int i,int j){
    if(rk[i] != rk[j]) return rk[i]<rk[j];
    else
    {
        int ri=i+k<=n?rk[i+k]:-1;
        int rj=j+k<=n?rk[j+k]:-1;
        return ri<rj;
    }
}
void build(char *s,int *sa)
{
    n=strlen(s);
    for(int i=0;i<=n;i++){
        sa[i]=i;
        rk[i]=i<n?s[i]:-1;
    }
    for(k=1;k<=n;k*=2){
        sort(sa,sa+n+1,cmp);
        tmp[sa[0]]=0;
        for(int i=1;i<=n;i++){
            tmp[sa[i]]=tmp[sa[i-1]]+(cmp(sa[i-1],sa[i])?1:0);
        }
        for(int i=0;i<=n;i++){
            rk[i]=tmp[i];
        }
    }
}
void LCP(char *s,int *sa,int *lcp){
    n=strlen(s);
    for(int i=0;i<=n;i++) rk[sa[i]]=i;
    int h=0;
    lcp[0]=0;
    for(int i=0;i<n;i++){
        int j=sa[rk[i]-1];
        for (h ? h-- : 0; j + h < n&&i + h < n&&s[j + h] == s[i + h]; h++);
        lcp[rk[i]-1] = h;
    }
}
struct node{
    ll x,y;
}st[N];
int main() {
    scanf("%s",s);
    n=strlen(s);
    build(s,sa);
    LCP(s,sa,lcp);
    //printf("@\n");
    ll cnt=0,ans=(ll)(n+1)*(ll)n/2,now=0;
    for(int i=0;i<n;i++){
        node tmp;
        tmp.x=lcp[i];
        //printf("!%d\n",lcp[i]);
        tmp.y=1;
        while(now>0&&st[now].x>tmp.x){
            tmp.y+=st[now].y;
            cnt-=st[now].x*st[now].y;
            now--;
        }
        st[++now]=tmp;
        cnt+=tmp.x*tmp.y;
        ans+=cnt;
    }
    cout<<ans<<endl;
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章