• BZOJ4650: [Noi2016]优秀的拆分


    BZOJ4650: [Noi2016]优秀的拆分

    Description

    如果一个字符串可以被拆分为 AABBAABB 的形式,其中 AA 和 BB 是任意非空字符串,则我们称该字符串的这种拆分是优秀的。
    例如,对于字符串 aabaabaa,如果令 A=aab,B=a,我们就找到了这个字符串拆分成 AABB 的一种方式。
    一个字符串可能没有优秀的拆分,也可能存在不止一种优秀的拆分。
    比如我们令 A=a,B=baa,也可以用 AABB 表示出上述字符串;但是,字符串 abaabaa 就没有优秀的拆分。
    现在给出一个长度为 n 的字符串 S,我们需要求出,在它所有子串的所有拆分方式中,优秀拆分的总个数。
    这里的子串是指字符串中连续的一段。
    以下事项需要注意:出现在不同位置的相同子串,我们认为是不同的子串,它们的优秀拆分均会被记入答案。
    在一个拆分中,允许出现 A=B。例如 cccc 存在拆分 A=B=c。字符串本身也是它的一个子串。

    Input

    每个输入文件包含多组数据。
    输入文件的第一行只有一个整数 T,表示数据的组数。
    保证 1≤T≤10。
    接下来 T 行,每行包含一个仅由英文小写字母构成的字符串 S,意义如题所述。

    Output

    输出 T 行,每行包含一个整数,表示字符串 S 所有子串的所有拆分中,总共有多少个是优秀的拆分。

    Sample Input

    4
    aabbbb
    cccccc
    aabaabaabaa
    bbaabaababaaba

    Sample Output

    3
    5
    4
    7

    HINT

    我们用 S[i,j] 表示字符串 S 第 i 个字符到第 j 个字符的子串(从 1 开始计数)。
    第一组数据中,共有 33 个子串存在优秀的拆分:
    S[1,4]=aabb,优秀的拆分为 A=a,B=b;
    S[3,6]=bbbb,优秀的拆分为 A=b,B=b;
    S[1,6]=aabbbb,优秀的拆分为 A=a,B=bb。
    而剩下的子串不存在优秀的拆分,所以第一组数据的答案是 3。
    第二组数据中,有两类,总共 4 个子串存在优秀的拆分:
    对于子串 S[1,4]=S[2,5]=S[3,6]=cccc,它们优秀的拆分相同,均为 A=c,B=c,但由于这些子串位置不同,因此要计算 3 次;
    对于子串 S[1,6]=cccccc,它优秀的拆分有 2 种:A=c,B=cc 和 A=cc,B=c,它们是相同子串的不同拆分,也都要计入答案。
    所以第二组数据的答案是 3+2=5
    第三组数据中,S[1,8] 和 S[4,11] 各有 2 种优秀的拆分,其中 S[1,8] 是问题描述中的例子,所以答案是 2+2=4。
    第四组数据中,S[1,4],S[6,11],S[7,12],S[2,11],S[1,8] 各有 1 种优秀的拆分,S[3,14] 有 2 种优秀的拆分,所以答案是 5+2=7。

    题解Here!
    感觉有点像后缀数组。。。
    没错就是后缀数组。

    显然我们不用处理什么$AABB$,只需要去处理所有$AA$的形式,再去统计答案即可。

    设$Left[i]$表示以$i$这个字符开头的$AA$型子串的数目。

    设$Right[i]$表示以$i$这个字符结尾的$AA$型子串的数目。

    则:$Ans=sum_{i=1}^{n-1}Left[i+1] imes Right[i]$

    顺序求一遍,反过来再求一遍,$Left[i],Right[i]$就可以求解了。

    问题是怎么求解。

    我们可以枚举找的$AA$型子串长度的一半,去判断$LCP$与$LCS$

    枚举$i=k imes len,j=i+len,j<=n$

    设$x=LCP(suffix(i),suffix(j)),y=LCS(prefix(i−1),prefix(j−1))$

    若$x+y>=len$,那么我们就找到了$x+y−len+1$个长度为$2 imes len$的$AA$型子串

    差分一下,最后做一遍前缀和即可。

    注:记得清空数组。。。

    附代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #define MAXN 50010
    using namespace std;
    int n;
    long long Left[MAXN],Right[MAXN];
    inline int read(){
        int date=0,w=1;char c=0;
        while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
        while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
        return date*w;
    }
    struct Suffix_Array{
        char str[MAXN];
        int top,sa[MAXN],rk[MAXN],tax[MAXN],tp[MAXN],height[MAXN],f[MAXN][20];
        void radixsort(){
            for(int i=0;i<=top;i++)tax[i]=0;
            for(int i=1;i<=n;i++)tax[rk[i]]++;
            for(int i=1;i<=top;i++)tax[i]+=tax[i-1];
            for(int i=n;i>=1;i--)sa[tax[rk[tp[i]]]--]=tp[i];
        }
        void suffixsort(){
            top=128;
            for(int i=1;i<=n;i++){
                rk[i]=str[i];
                tp[i]=i;
            }
            radixsort();
            for(int w=1,p=0;p<n;top=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;
                radixsort();
                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;
            }
        }
        void getheight(){
            for(int i=1,j,k=0;i<=n;i++){
                if(k)k--;
                j=sa[rk[i]-1];
                while(str[i+k]==str[j+k])k++;
                height[rk[i]]=k;
            }
        }
        void step(){
            for(int i=1;i<=n;i++)f[i][0]=height[i];
            for(int i=1;(1<<i)<=n;i++)
            for(int j=1;j+(1<<i)-1<=n;j++)
            f[j][i]=min(f[j][i-1],f[j+(1<<(i-1))][i-1]);
        }
        int query(int l,int r){
            l=rk[l];r=rk[r];
            if(l>r)swap(l,r);
            l++;
            int k=(int)log2(r-l+1);
            return min(f[l][k],f[r-(1<<k)+1][k]);
        }
        inline void clean(){
            memset(str,0,sizeof(str));
            memset(sa,0,sizeof(sa));
            memset(rk,0,sizeof(rk));
            memset(height,0,sizeof(height));
            memset(tp,0,sizeof(tp));
            memset(f,0,sizeof(f));
        }
        inline void build(){
            suffixsort();
            getheight();
            step();
        }
    }A,B;
    void work(){
        long long ans=0;
        for(int k=1;k<=(n>>1);k++)
        for(int i=k,j=i+k;j<=n;i+=k,j+=k){
            int x=min(k,A.query(i,j)),y=min(k-1,B.query(n-(i-1)+1,n-(j-1)+1));
            if(x+y>=k){
                int t=x+y-k+1;
                Left[i-y]++;Left[i-y+t]--;
                Right[j+x-t]++;Right[j+x]--;
            }
        }
        for(int i=1;i<=n;i++){
            Left[i]+=Left[i-1];
            Right[i]+=Right[i-1];
        }
        for(int i=1;i<=n;i++)ans+=Left[i+1]*Right[i];
        printf("%lld
    ",ans);
    }
    void init(){
        memset(Left,0,sizeof(Left));
        memset(Right,0,sizeof(Right));
        A.clean();B.clean();
        scanf("%s",A.str+1);
        n=strlen(A.str+1);
        for(int i=1;i<=n;i++)B.str[i]=A.str[n-i+1];
        A.build();B.build();
    }
    int main(){
        int t=read();
        while(t--){
            init();
            work();
        }
        return 0;
    }
    
  • 相关阅读:
    原创:USB HID读卡器数据解析(R321-13.56MHZ读卡器)
    你对USB了解吗?--USB 协议分析之 HID 设备
    Python中的单例设计模式【多测师_王sir】
    把一个json文件写入到csv文件当中【多测师_王sir】
    pip安装本地文件报错处理方法【多测师_王sir】
    ddt数据驱动常见的用法【多测师_王sir】
    读取json数据转换为字典存入到列表当中【多测师_王sir】
    读取json数据输入键拿到对应的值【多测师_王sir】
    为什么要用cookie和session【多测师_王sir】
    Python2和Python3的区别【多测师_王sir】
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9458910.html
Copyright © 2020-2023  润新知