• bzoj3879: SvT(后缀数组+st表+单调栈)


    https://www.lydsy.com/JudgeOnline/problem.php?id=3879

    把所有的后缀取出,按rank排序

    求出相邻两个后缀的lcp

    每个后缀对答案的贡献就是 与在它之前的后缀的lcp之和

    维护一个单调递增的栈,记录栈中元素的lcp之和 即可

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    
    #define N 500001
    #define M 3000001
    
    int n,m,mm;
    char s[N];
    int a[N];
    
    int b[M],r[N];
    
    int v[N];
    int p,q=1,k;
    int sa[2][N],rk[2][N];
    
    int height[N],h[N];
    int st[N][16];
    
    int Log[N];
    
    int ST[N],top;
    int num[N],val[N];
    
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    
    void mul(int *sa,int *rk,int *SA,int *RK)
    {
        for(int i=1;i<=n;++i) v[rk[sa[i]]]=i;
        for(int i=n;i;--i) if(sa[i]>k) SA[v[rk[sa[i]-k]]--]=sa[i]-k;
        for(int i=n-k+1;i<=n;++i) SA[v[rk[i]]--]=i;
        for(int i=1;i<=n;++i) RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i]]!=rk[SA[i-1]] || rk[SA[i]+k]!=rk[SA[i-1]+k]);
    }
    
    void presa()
    {
        for(int i=1;i<=n;++i) v[a[i]]++;
        for(int i=1;i<=26;++i) v[i]+=v[i-1];
        for(int i=1;i<=n;++i) sa[p][v[a[i]]--]=i;
        for(int i=1;i<=n;++i) rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(a[sa[p][i]]!=a[sa[p][i-1]]);
        for(k=1;k<n;k<<=1,swap(p,q)) mul(sa[p],rk[p],sa[q],rk[q]);
    }
    
    void get_height()
    {
        int k=0,j;
        for(int i=1;i<=n;++i)
        {
            j=sa[p][rk[p][i]-1];
            while(a[i+k]==a[j+k]) k++;
            height[rk[p][i]]=k;
            if(k) k--;
        }
    }
    
    void prest()
    {
        for(int i=2;i<=n;++i) st[i][0]=height[i];
        for(int i=1,k=2;i<=15;++i,k<<=1)
            for(int j=2;j+k-1<=n;++j) 
                st[j][i]=min(st[j][i-1],st[j+k/2][i-1]);
    }
    
    int get(int i,int j)
    {
        i++;
        int l=Log[j-i+1];
        return min(st[i][l],st[j-(1<<l)+1][l]);
    }
    
    void solve()
    {
        for(int i=1;i<=mm;++i) r[i]=rk[p][b[i]];
        sort(r+1,r+mm+1);
        for(int i=2;i<=mm;++i) h[i]=get(r[i-1],r[i]);
        top=0;
        int tmp_num;
        long long now=0,ans=0;
        for(int i=2;i<=mm;++i)
        {
            tmp_num=0;
            while(top && h[i]<=h[ST[top]]) 
            {
                now-=1LL*num[top]*val[top];
                tmp_num+=num[top--];
            }
            tmp_num++;
            ST[++top]=i;
            num[top]=tmp_num;
            val[top]=h[i];
            now+=1LL*tmp_num*h[i];
            ans+=now;
        }
        cout<<ans<<'
    ';
    }
    
    int main()
    {
        int T;
        read(n); read(T);
        for(int i=2;i<=n;++i) Log[i]=Log[i>>1]+1;
        scanf("%s",s+1);
        for(int i=1;i<=n;++i) a[i]=s[i]-'a'+1;
        presa();
        get_height();
        prest();
        while(T--)
        {
            read(m);
            for(int i=1;i<=m;++i) read(b[i]);
            sort(b+1,b+m+1);
            mm=unique(b+1,b+m+1)-b-1;
            solve();
        }
    }
  • 相关阅读:
    sublime text 3安装 package control 插件的方法
    mysql 库和表占用空间查询
    错误:编码GBK的不可映射字符
    新系统设置 github 私钥
    git 之忽略文件 gitignore 创建和使用规则
    DesiredCapabilities内容详解(摘)
    appium-python自动化之get_attribute笔记(摘)
    excel批量插入图片-方法(宏和纯手工操作)
    利用Python将多个excel文件合并为一个文件
    notePad++ 运行python
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8977430.html
Copyright © 2020-2023  润新知