zoukankan      html  css  js  c++  java
  • bzoj 3238: [AHOI2013]差异

                    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 3748  Solved: 1697
    [Submit][Status][Discuss]

    Description

    一个长度为N的字符串S,求Σ(任意两个后缀的长度和-它们lcp长度的两倍)

    Input

    一行,一个字符串S

    Output

    一行,一个整数,表示所求值

    Sample Input

    cacao

    Sample Output


    54

    HINT



    2<=N<=500000,S由小写英文字母组成


    我们知道光是后缀数组是没有什么用的,但是后缀数组可以用来求LCP,原理就是rmq。
    求LCP的话需要在原基础上加一个height函数,代表后缀排序之后的数组的相邻位置的LCP。
    这样的话求任意两个位置的LCP就变成了求一段区间的rmq。
    求height可以做到O(N),需要用到一个玄学的单调性。。。。得按照在原序列中的位置计算。

    然后小推一波式子题目就出来了(注意height[1]是0)。

    #include<bits/stdc++.h>
    #define ll long long
    #define maxn 500005
    using namespace std;
    ll ans=0,tot=0;
    char s[maxn];
    int n,m,st[maxn],tp=0;
    int sa[maxn],sax[maxn];
    int sec[maxn],cc[maxn];
    int rank[maxn<<1],rankx[maxn];
    int height[maxn],now,k;
    
    inline void get_height(){
        for(int i=0;i<n;i++) cc[s[i]]++;
        for(int i=1;i<=500;i++) cc[i]+=cc[i-1];
        for(int i=0;i<n;i++) sa[cc[s[i]]--]=i;
        for(int i=1;i<=n;i++){
            rank[sa[i]]=i;
            if(i>1&&s[sa[i]]==s[sa[i-1]]) rank[sa[i]]=rank[sa[i-1]];
        }
        
        int len=1;
        while(len<n){
            memset(cc,0,sizeof(cc));
            for(int i=0;i<n;i++) cc[sec[i]=rank[i+len]]++;
            for(int i=n-1;i>=0;i--) cc[i]+=cc[i+1];
            for(int i=0;i<n;i++) sax[cc[sec[i]]--]=i;
            
            memset(cc,0,sizeof(cc));
            for(int i=0;i<n;i++) cc[rank[i]]++;
            for(int i=1;i<=n;i++) cc[i]+=cc[i-1];
            for(int i=1;i<=n;i++) sa[cc[rank[sax[i]]]--]=sax[i];
            
            for(int i=1;i<=n;i++){
                rankx[sa[i]]=i;
                if(i>1&&rank[sa[i]]==rank[sa[i-1]]&&sec[sa[i]]==sec[sa[i-1]]) rankx[sa[i]]=rankx[sa[i-1]];
            }
            
            for(int i=0;i<n;i++) rank[i]=rankx[i];
            len<<=1;
        }
        
        int now=0,j,mx;
        for(int i=0;i<n;i++){
            if(rank[i]==1){
                now=0,height[1]=0;
                continue;
            }
            if(now) now--;
            
            j=sa[rank[i]-1];
            mx=max(j,i);
            while(mx+now<n&&s[i+now]==s[j+now]) now++;
            height[rank[i]]=now;
        }
    }
    
    inline void solve(){
        ans=n*(ll)(n+1)*(ll)(n-1)>>1ll;
        for(int i=1;i<=n;i++){
            while(tp&&height[st[tp]]>=height[i]) tp--;
            st[++tp]=i;
            for(int j=tp;j;j--) tot+=(ll)(st[j]-st[j-1])*(ll)height[st[j]];
        }
        ans-=tot<<1ll;
    }
    
    int main(){
        scanf("%s",s);
        n=strlen(s);
        get_height();
        solve();
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    根据模板自动生成数据
    CSV to XLSX (专用)
    释放用完的Excel COM组件
    配置文件的力量
    字符编解码的故事(ASCII,ANSI,Unicode,Utf-8区别)
    将结果中的省略号内容全部输出
    Powershell变量的类型
    一些用过的C#类库收集
    运算符
    特殊运算符
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8278296.html
Copyright © 2011-2022 走看看