zoukankan      html  css  js  c++  java
  • bzoj3238 [Ahoi2013]差异

    传送门

    分析

    首先把式子分开

    我们知道lcp(i,j) = min(height[i+1],height[i+2],......,height[j])

    于是我们可以对于每个点求出它作为min的区间

    于是左端点范围[le-1,i-1],右端点范围[i,ri]

    这个题就解决了

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<cctype>
    #include<cmath>
    #include<cstdlib>
    #include<ctime>
    #include<queue>
    #include<vector>
    #include<set>
    #include<map>
    #include<stack>
    using namespace std;
    char s[500100];
    int n,m=128,rk[500100],sa[500100],tax[500100],tp[500100],h[500100],height[500100];
    inline void qsort(){
        for(int i=0;i<=m;i++)tax[i]=0;
        for(int i=1;i<=n;i++)tax[rk[i]]++;
        for(int i=1;i<=m;i++)tax[i]+=tax[i-1];
        for(int i=n;i>0;i--)sa[tax[rk[tp[i]]]--]=tp[i];
    }
    inline void work(){
        for(int i=1;i<=n;i++)rk[i]=s[i]-'0'+1,tp[i]=i;qsort();
        for(int w=1,p=0;p<n;m=p,w<<1){
          p=0;for(int i=1;i<=w;++i)tp[++p]=n-w+i;
          for(int i=1;i<=n;++i)if(sa[i]>w)tp[++p]=sa[i]-w;
          qsort();swap(tp,rk);rk[sa[1]]=p=1;
          for(int i=2;i<=n;++i)
            rk[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w])?p:++p;
        }
        for(int i=1;i<=n;++i)rk[sa[i]]=i;h[0]=0;
        for(int i=1;i<=n;++i){
          h[i]=max(h[i-1]-1,0);
          while(i+h[i]<=n&&sa[rk[i]-1]+h[i]<=n&&s[i+h[i]]==s[sa[rk[i]-1]+h[i]])h[i]++;
        }
        for(int i=1;i<=n;++i)height[i]=h[sa[i]];
    }
    int le[500100],ri[500100],a[500100],pl[500100],cnt;
    int main(){
        int i,j,k;
        long long Ans=0;
        scanf("%s",s+1);
        n=strlen(s+1);
        work();
        for(i=1;i<=n;++i)Ans+=1ll*i*(n-1);
        cnt=0;
        a[++cnt]=height[1];
        le[1]=1;
        pl[1]=1;
        for(i=2;i<=n;++i){
          while(cnt&&a[cnt]>=height[i])--cnt;
          if(!cnt)le[i]=1;
            else le[i]=pl[cnt]+1;
          a[++cnt]=height[i];
          pl[cnt]=i;
        }
        cnt=0;
        a[++cnt]=height[n];
        ri[n]=n;
        pl[1]=n;
        for(i=n-1;i>0;--i){
          while(cnt&&a[cnt]>height[i])--cnt;
          if(!cnt)ri[i]=n;
            else ri[i]=pl[cnt]-1;
          a[++cnt]=height[i];
          pl[cnt]=i;
        }
        for(i=1;i<=n;++i)Ans-=2ll*height[i]*(ri[i]-i+1)*(i-le[i]+1);
        printf("%lld
    ",Ans);
        return 0;
    }
  • 相关阅读:
    数论 欧几里德算法 以及 欧几里得拓展
    数论 快速幂的原理讲解
    汉诺塔模板
    C++ 迭代器运算
    C++ STL vector set map 简易用法
    C++ 使用指向函数的指针数组
    Codeforces 718C 线段树+矩乘
    BZOJ 2506 分块
    Codeforces 455D 分块+链表
    Codeforces 19E 树上差分
  • 原文地址:https://www.cnblogs.com/yzxverygood/p/10606098.html
Copyright © 2011-2022 走看看