• 【BZOJ-3238】差异 后缀数组 + 单调栈


    3238: [Ahoi2013]差异

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 1561  Solved: 734
    [Submit][Status][Discuss]

    Description

    Input

    一行,一个字符串S

    Output

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

    Sample Input

    cacao

    Sample Output

    54

    HINT

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

    Source

    Solution

    后缀数组+单调栈

    LCP的话,预处理ST表,然后直接求?似乎不好,不过后缀数组的话很好想

    肯定是对height做文章...总后缀的长度和很好求..随便一算就出来了...考虑LCP的问题

    想法是枚举i,对于每个height[i]前后扩展,找出对答案的贡献,然后最后计算答案..似乎可以,但是WA掉了..

    原因是有重复计算,那么要不重复..上述是左右两边扩展,使得区间[l,r]中height[i]为最小,重复的很多,思想还是一样的不过不妨把区间看成[l,r)(PS,其实表述不准确),这样的扩展下去,即向左有限制,向右无限制,向左扩展到相等的就停止,向右遇到相等的可以继续.

    那么需要用单调栈去维护扩展的过程..这样就能得到每一个height[i]对答案的贡献了,最后答案需要减掉(i-L[i]+1)*(R[i]-i+1)*(height[i])

    注意:

    在计算答案的过程中要强制转换.(旧错不再犯)

    处理后的单调栈内如果为空,说明可以扩展到开头/结尾(也是看别人的才反应过来的)

    PS:正解好像不是这个?...不过POJ上好像做过类似的题,所以写起来还是比较快的..

    Code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    #define maxn 500010
    char S[maxn]; int SA[maxn],len;
    int ws[maxn],wv[maxn],wa[maxn],wb[maxn];
    int cmp(int *r,int a,int b,int l)
    {
        return r[a]==r[b]&&r[a+l]==r[b+l];
    }
    void DA(char *r,int *sa,int n,int m)
    {
        int p,*x=wa,*y=wb,*t;
        for (int i=0; i<m; i++) ws[i]=0;
        for (int i=0; i<n; i++) ws[x[i]=r[i]]++;
        for (int i=1; i<m; i++) ws[i]+=ws[i-1];
        for (int i=n-1; i>=0; i--) sa[--ws[x[i]]]=i;
        p=1; for (int j=1; p<n; j*=2,m=p)
            {
                p=0; for (int i=n-j; i<n; i++) y[p++]=i;
                for (int i=0; i<n; i++) if (sa[i]>=j) y[p++]=sa[i]-j;
                for (int i=0; i<n; i++) wv[i]=x[y[i]];
                for (int i=0; i<m; i++) ws[i]=0;
                for (int i=0; i<n; i++) ws[wv[i]]++;
                for (int i=1; i<m; i++) ws[i]+=ws[i-1];
                for (int i=n-1; i>=0; i--) sa[--ws[wv[i]]]=y[i];
                t=x; x=y; y=t; p=1; x[sa[0]]=0;
                for (int i=1; i<n; i++) 
                    x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
            } 
    }
    int rank[maxn],height[maxn];
    void calheight(char *r,int *sa,int n)
    {
        int k=0;
        for (int i=1; i<=n; i++) rank[sa[i]]=i;
        for (int i=0; i<n; height[rank[i++]]=k)
            {k?k--:0;for (int j=sa[rank[i]-1]; r[i+k]==r[j+k]; k++);}
    }
    int stack[maxn],top,L[maxn],R[maxn];
    long long tot,lcp;
    int main()
    {
        scanf("%s",S); len=strlen(S); S[len]=0;
        DA(S,SA,len+1,128);  calheight(S,SA,len);
        tot=(long long)((long long)len*(long long)(len-1)*(long long)(len+1)/2);
        top=1; stack[0]=1;
        for (int i=1; i<=len; i++)
            {
                while (top && height[stack[top-1]]>height[i]) top--;
                if (top) L[i]=stack[top-1]+1;
                else L[i]=1;
                stack[top++]=i;
            }
        top=1; stack[0]=len;
        for (int i=len; i>=1; i--)
            {
                while (top && height[stack[top-1]]>=height[i]) top--;
                if (top) R[i]=stack[top-1]-1;
                else R[i]=len;
                stack[top++]=i; 
            }
        for (int i=2; i<=len; i++)
            lcp+=(long long)2*(long long)(i-L[i]+1)*(long long)(R[i]-i+1)*(long long)height[i];
        printf("%lld
    ",tot-lcp);
        return 0;
    }
  • 相关阅读:
    python
    VSCompile
    Oracle学习
    CMD
    JQuery 学习
    单词
    解决Manjaro+win双系统相差8小时
    编辑器使用
    软件安装
    磁盘分区与逻辑卷管理
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5429832.html
Copyright © 2020-2023  润新知