zoukankan      html  css  js  c++  java
  • #4247. 串

    题意
    内存限制:1024 MiB
    时间限制:1000 ms

    zzq 喜欢做傻吊题。

    一天,zzq 正在和往常一样做一个傻吊题:输入一个串,输出它共有多少个本质不同的子串。这里 本质不同指的是长得不一样。由于这是一道 FJOI 题,字符只有 `{A,C,G,T}` 四种。zzq 写了一个后缀 数组,调了半小时通过了。zzq 感觉这个题没啥意思,应该加强一下。

    记 $f(S)$ 为 $S$ 的最小表示,具体地,把 $S$ 中第一次出现的字母替换为 `a`,第二次出现的字母替换 为 `b`,等等。例如,$f($`AGACC`$) =$`abacc`。题意仍然是输入一个串,输出它共有多少个本质不同的子串,但是现在两个串 $A$ 和 $B$ 本质不同定义为 $f(A)$ 与 $f(B)$ 不同。

    由于现在这个题没那么傻吊了,zzq 不会做了。他想请你解决这个问题。

    $n ≤ 10^5$
    题解
    对于最小表示法,发现只有 $24$ 种映射关系,于是预处理出这 $24$ 种映射关系的 $hash$ 值

    对于每个后缀,可以找出它的映射关系

    根据 $SA$ 的思想,将所有后缀按照映射后的字典序排序,然后答案就是 $frac{n imes (n+1)}{2}-sum_{i=2}^n lcp(s_{i-1},s_i)$

    对于求 $lcp$ ,可以二分 $hash$ ,对于排序,可以在 $cmp$ 中调用求 $lcp$ 的函数,然后只需要比较下一位或串长即可

    代码

    #include <bits/stdc++.h>
    #define K 793999
    #define I inline
    #define U unsigned long long
    using namespace std;
    const int N=1e5+5;
    int n,p[6],D[150],S[5],a[N],t=-1;
    char s[N],F[5];U b[N];long long ans;
    struct O{
        char f[5];int d[150];U h[N];
        I U H(int l,int r){
            return h[r]-h[l-1]*b[r-l+1];
        }
    }g[24];
    struct Q{int h,ty;}q[N];
    I bool newap(int x,int y){return S[x]<S[y];}
    I int get(){
        for (int i=1;i<=4;i++) p[i]=i;
        sort(p+1,p+5,newap);
        for (int i=0;i<24;i++){
            bool J=1;
            for (int j=1;j<=4;j++)
                J&=(F[p[j]]==g[i].f[j]);
            if (J) return i;
        }
    }
    I int lcp(int x,int y){
        int l=0,h1=q[x].h,h2=q[y].h,r=min(n-h1+1,n-h2+1),t1=q[x].ty,t2=q[y].ty;
        while(l<r){
            int mid=(l+r+1)>>1;
            if (g[t1].H(h1,h1+mid-1)==g[t2].H(h2,h2+mid-1))
                l=mid;
            else r=mid-1;
        }
        return l;
    }
    I bool cmp(int x,int y){
        int l=lcp(x,y);
        if (l==min(n-q[x].h+1,n-q[y].h+1))
            return q[x].h>q[y].h;
        int u=g[q[x].ty].d[(int)s[q[x].h+l]];
        int v=g[q[y].ty].d[(int)s[q[y].h+l]];
        return u<v;
    }
    int main(){
        scanf("%s",s+1);n=strlen(s+1);ans=1ll*n*(n+1)/2;
        b[0]=1;for (int i=1;i<=4;i++) p[i]=i;
        S[D[(int)(F[1]='A')]=1]=n+1;
        S[D[(int)(F[2]='C')]=2]=n+1;
        S[D[(int)(F[3]='G')]=3]=n+1;
        S[D[(int)(F[4]='T')]=4]=n+1;
        for (int i=1;i<=n;i++) b[i]=b[i-1]*K;
        do{
            t++;for (int i=1;i<=4;i++)
                g[t].f[i]=F[p[i]],g[t].d[(int)F[p[i]]]=i;
            for (int i=1;i<=n;i++)
                g[t].h[i]=g[t].h[i-1]*K+g[t].d[(int)s[i]];
        }while(next_permutation(p+1,p+5));
        for (int i=n;i;i--)
            S[D[(int)s[i]]]=i,q[i]=(Q){i,get()},a[i]=i;
        sort(a+1,a+n+1,cmp);
        for (int i=2;i<=n;i++) ans-=lcp(a[i-1],a[i]);
        return printf("%lld
    ",ans),0;
    }
  • 相关阅读:
    《何以为家》--观影心得
    博弈论 -- 巴什博弈
    《黑客攻防技术-系统实战》第二章--栈溢出1
    《汇编语言》--程序范例
    《黑客攻防技术-系统实战》开篇讲解
    ptrace理解
    DPDK初始化
    C++ 对象内存模型
    DPDK学习路线计划
    DPDK学习开篇
  • 原文地址:https://www.cnblogs.com/xjqxjq/p/10679485.html
Copyright © 2011-2022 走看看