BZOJ 4650([Noi2016]优秀的拆分-SA)

Description

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

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

Output

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

4

aabbbb

cccccc

aabaabaabaa

bbaabaababaaba
Sample Output

3

5

4

7

explanation

我们用 S[i,j]S[i,j] 表示字符串 SS 第 ii 个字符到第 jj 个字符的子串(从 11 开始计数)。

第一组数据中,共有 33 个子串存在优秀的拆分:

S[1,4]=aabbS[1,4]=aabb,优秀的拆分为 A=aA=a,B=bB=b;

S[3,6]=bbbbS[3,6]=bbbb,优秀的拆分为 A=bA=b,B=bB=b;

S[1,6]=aabbbbS[1,6]=aabbbb,优秀的拆分为 A=aA=a,B=bbB=bb。

而剩下的子串不存在优秀的拆分,所以第一组数据的答案是 33。

第二组数据中,有两类,总共 44 个子串存在优秀的拆分:

对于子串 S[1,4]=S[2,5]=S[3,6]=ccccS[1,4]=S[2,5]=S[3,6]=cccc,它们优秀的拆分相同,均为 A=cA=c,B=cB=c,但由于这些子串位置不同,因此要计算 33 次;

对于子串 S[1,6]=ccccccS[1,6]=cccccc,它优秀的拆分有 22 种:A=cA=c,B=ccB=cc 和 A=ccA=cc,B=cB=c,它们是相同子串的不同拆分,也都要计入答案。

所以第二组数据的答案是 3+2=53+2=5。

第三组数据中,S[1,8]S[1,8] 和 S[4,11]S[4,11] 各有 22 种优秀的拆分,其中 S[1,8]S[1,8] 是问题描述中的例子,所以答案是 2+2=42+2=4。

第四组数据中,S[1,4]S[1,4],S[6,11]S[6,11],S[7,12]S[7,12],S[2,11]S[2,11],S[1,8]S[1,8] 各有 11 种优秀的拆分,S[3,14]S[3,14] 有 22 种优秀的拆分,所以答案是 5+2=75+2=7。
HINT

这个SA用的十分巧妙
膜拜大神题解:http://www.cnblogs.com/clrs97/p/5731321.html

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXN (60010)
#define Sigma_size (256)
typedef long long ll;
class SA
{
public:
    char s[MAXN];
    int sa[MAXN],t[MAXN],t2[MAXN],c[MAXN],n;    
    SA(){}
    void mem(char *_s){memcpy(s,_s,sizeof(s));n=strlen(s);MEM(sa) MEM(t) MEM(t2) MEM(c) MEM(height) MEM(rank) }
    void build_sa(int m)
    {
        int *x=t,*y=t2;
        Rep(i,m) c[i]=0;
        Rep(i,n) c[x[i]=s[i]]++; 
        For(i,m-1) c[i]+=c[i-1];
        RepD(i,n-1) sa[--c[x[i]]]=i;
        for(int k=1;k<=n;k<<=1)
        {
            int p=0;
            ForkD(i,n-k,n-1) y[p++]=i;
            Rep(i,n) if (sa[i]>=k) y[p++]=sa[i]-k; 

            Rep(i,m) c[i]=0;
            Rep(i,n) c[x[y[i]]]++;  
            For(i,m-1) c[i]+=c[i-1];
            RepD(i,n-1) sa[--c[x[y[i]]]]=y[i];
            swap(x,y);  
            p=1; x[sa[0]]=0;
            For(i,n-1)
                x[sa[i]]=(y[sa[i-1]]==y[sa[i]]&&y[sa[i]+k]==y[sa[i-1]+k]) ? (p-1):(p++);
            if (p>=n) break;
            m=p;
        }
    }
    int rank[MAXN],height[MAXN];
    void make_height()
    {
        int k=0;
        Rep(i,n) rank[sa[i]]=i;
        Rep(i,n)
        {
            if (rank[i]-1<0) continue;
            if (k) k--;
            int j=sa[rank[i]-1];
            while(max(i,j)+k<n&&s[i+k]==s[j+k]) ++k;
            height[rank[i]]=k;
        }
    }
    #define MAXLog (20)
    int d[MAXN][MAXLog];
    void RMQ_init()
    {
        Rep(i,n) d[i][0]=height[i];
        for(int j=1;(1<<j)<=n;j++)
            for(int i=0;i + (1<<j) -1 < n; i++)
            {
                d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]);
            }
    } 
    int query(int L,int R)
    {
        if (L>R) swap(L,R);
        int k=floor(log(R-L+1)/log(2));
        return min(d[L][k],d[R-(1<<k)+1][k]);
    }
    int lcp(int x,int y) {
        x=rank[x],y=rank[y];
        if (x>y) swap(x,y);
        return query(x+1,y);
    }
}S,rS;
int n;
char s[MAXN];
int lcp(int x,int y) { return S.lcp(x-1,y-1);}
int lcs(int x,int y) { return rS.lcp(n-x,n-y);}
ll f[MAXN],g[MAXN];
void calc() {
    MEM(f) MEM(g)
    For(i,n/2) {
        for(int j=2*i;j<=n;j+=i) 
            if (s[j-1]==s[j-i-1]) {
                int x=lcs(j,j-i),y=lcp(j,j-i);
                int r=min(j+y-1,min(j+i-1,n));
                int l=max(j-i-x+1+2*i-1,j);
                if (l<=r) {
                    f[l]++; f[r+1]--;
                    g[l-2*i+1]++; g[r-2*i+2]--;
                }
            }
    }
    For(i,n) f[i]+=f[i-1],g[i]+=g[i-1];
    ll ans=0; For(i,n-1) ans+=(ll)f[i]*g[i+1];
    cout<<ans<<endl;
}
int main()
{
//  freopen("bzoj4650.in","r",stdin);
//  freopen("bzoj4650.out","w",stdout);
    int T; cin>>T;
    while(T--) {
        MEM(s) 
        scanf("%s",s);
        n=strlen(s);
        S.mem(s);
        S.build_sa(Sigma_size);
        S.make_height();
        S.RMQ_init();
        reverse(s,s+n);
        rS.mem(s);
        rS.build_sa(Sigma_size);
        rS.make_height();
        rS.RMQ_init();
        reverse(s,s+n);
        calc(); 
    }   
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值