• BZOJ3238: [Ahoi2013]差异


    3238: [Ahoi2013]差异

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 4840  Solved: 2298
    [Submit][Status][Discuss]

    Description

    Input

    一行,一个字符串S

    Output

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

    Sample Input

    cacao

    Sample Output


    54

    HINT



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

    Source

     
    [Submit][Status][Discuss]

    题解:这题曾用后缀数组做过,因为那时候来不及也学不会SAM,就对着GXZlegend的博客学了一遍打了一遍,然后就忘了,那就SAM来写一遍吧。其实这也算是个论文题,2015国家集训队论文中有提到,虽然其实很简单。就是把原串反过来建SAM可以得到后缀树,然后两个后缀的最长公共前缀就变成了lca的深度(其实我是不懂后缀树的,但是yy一下就起码能意会是这样),于是计算每个点的贡献就好了,这,,就是很“熟悉”的树形dp呀,直接这个节点的节点数C(n,2)就是了,然后每个点的深度就是max-min+1,即sr[a].len-sr[sr[a].ff].len。前面那部分暴力算,每个点都出现了n-1次。

    #include<bits/stdc++.h>
    #define pb push_back
    #define mp make_pair
    #define ll long long
    using namespace std;
    const int maxn=1e6+100;
    char s[maxn];
    struct str
    {
        int son[26];
        int ff,len;
    }sr[maxn];
    int cnt=1,last=1;
    int siz[maxn],c[maxn],a[maxn];
    void extend(int c)
    {
       int p=last,np=++cnt;last=np;
       sr[np].len=sr[p].len+1;
       while(p&&!sr[p].son[c])sr[p].son[c]=np,p=sr[p].ff;
       if(!p)sr[np].ff=1;
       else
       {
           int q=sr[p].son[c];
           if(sr[p].len+1==sr[q].len)sr[np].ff=q;
           else
           {
               int nq=++cnt;
               sr[nq]=sr[q];
               sr[nq].len=sr[p].len+1;
               sr[q].ff=sr[np].ff=nq;
               while(p&&sr[p].son[c]==q)sr[p].son[c]=nq,p=sr[p].ff;
           }
       }
       siz[np]=1;
    }
    int main()
    {
        int t;
            scanf("%s",s+1);
            int len=strlen(s+1);
            //memset(sr,0,sizeof(sr));
            cnt=1;last=1;
            for(int i=len;i;i--)extend(s[i]-'a');
            for(int i=1;i<=cnt;i++)c[sr[i].len]++;
            for(int i=1;i<=cnt;i++)c[i]+=c[i-1];
            for(int i=1;i<=cnt;i++)a[c[sr[i].len]--]=i;
            for(int i=cnt;i;i--)siz[sr[a[i]].ff]+=siz[a[i]];
            ll ans=0;
            for(int i=1;i<=len;i++)ans+=1ll*i*(len-1);
            for(int i=1;i<=cnt;i++)ans-=1ll*siz[i]*(siz[i]-1)*(sr[i].len-sr[sr[i].ff].len);
            cout<<ans<<"
    ";
    }
    

      后缀数组就先只贴代码了,用了单调栈。。EC前的没有脑子的代码。

    #include<bits/stdc++.h>
    #define ll long long
    #define pb push_back
    #define ill inline
    #define mp make_pair
    #define db double
    #define eps 1e-9
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=5e5+7;
    const double pi=acos(-1);
    inline ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int rankk[maxn],sa[maxn],x[maxn],y[maxn],c[maxn],height[maxn];
    int sta[maxn],l[maxn],r[maxn];
    char S[maxn];
    int ps[maxn];
    int n,m,top;
    void da()
    {
        m=27;int i,j,p;
        for(i=0;i<n;i++)c[x[i]=ps[i]]++;
        for(i=1;i<m;i++)c[i]+=c[i-1];
        for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
        for( p=1,j=1;p<n;j<<=1,m=p)
        {
            for(p=0,i=n-j;i<n;i++)y[p++]=i;
            for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
            for(i=0;i<m;i++)c[i]=0;
            for(i=0;i<n;i++)c[x[y[i]]]++;
            for(i=1;i<m;i++)c[i]+=c[i-1];
            for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
            for(swap(x,y),p=i=1,x[sa[0]]=0;i<n;i++)
            {
                if(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j])x[sa[i]]=p-1;
                else x[sa[i]]=p++;
            }
        }
        for(i=1;i<n;i++)rankk[sa[i]]=i;
        for(p=i=0;i<n-1;height[rankk[i++]]=p)
            for(p?p--:p,j=sa[rankk[i]-1];ps[i+p]==ps[j+p];p++);
    }
    int main()
    {
        scanf("%s",S);
        n=strlen(S);
        int i;
        for(i=0;i<n;i++)ps[i]=S[i]-'a'+1;
        n++;da();n--;
        sta[0]=1;
        for(i=2;i<=n;i++)
        {
            while(top&&height[sta[top]]>=height[i])top--;
            l[i]=i-sta[top],sta[++top]=i;
        }
        top=0,sta[0]=n+1;
        for(i=n;i>=2;i--)
        {
            while(top&&height[sta[top]]>height[i])top--;
            r[i]=sta[top]-i,sta[++top]=i;
        }
        ll ans=0;
        for(i=2;i<=n;i++)ans+=2ll*r[i]*l[i]*height[i];
            cout<<1ll*n*(n+1)*(n-1)/2-ans<<"
    ";
    }
    

      

  • 相关阅读:
    go-elasticsearch 来自官方的 golang es client
    nginx unit nodejs 模块试用(续)
    WebSocket-Over-HTTP Protocol
    pushpin Server-sent events && openresty 集成试用
    Rendering on the Web
    pushpin openresty 集成试用
    100 webhook implementations
    streamdataio 实时数据分发平台
    Generic Realtime Intermediary Protocol
    Pushpin How it works
  • 原文地址:https://www.cnblogs.com/intwentieth/p/10415616.html
Copyright © 2020-2023  润新知