BZOJ 4650: [Noi2016]优秀的拆分

题意:给你一个串,让你找出AABB型的子串有多少种,A可以为一个字符串,但A≠B

思路:我觉得这篇讲的很清楚(传送门),我觉得这个题只有在lcp的那个地方不是很容易想到,从来没想过lcp还可以这么用,代码是搬运claris小姐姐

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=80005;
char s[maxn];
int T,n,Log[maxn],l,r,f[maxn],g[maxn];
LL ans;
/**
在使用后缀数组时要先进行倍增预处理,调用init_suffix
s为字符串
sa为后缀数组,记录排序后的后缀数组的位置
rk为记录以i开始的后缀在后缀数组中的位置
height为高度数组,表示排序后相邻的两个后缀的公共前缀
lcp函数可以查两个位置的lcp公共长度
*/
void init_suffix()
{
    for(int i=2;i<maxn;i++)Log[i]=Log[i>>1]+1;
}
struct SuffixArray
{
    char s[maxn];
    int sa[maxn],rk[maxn],height[maxn],tmp[maxn],cnt[maxn],f[15][maxn],len;
    inline void init()
    {
        for(int i=0;i<len*2+5;i++)s[i]=0;
    }
    inline void suffix(int m)
    {
        int i,j,k,len1=len+1;;
        for(i=0;i<len1*2+5;i++)rk[i]=sa[i]=height[i]=tmp[i]=0;
        for(i=0;i<m;i++)cnt[i]=0;
        for(i=0;i<len1;i++)cnt[rk[i]=s[i]]++;
        for(i=1;i<m;i++)cnt[i]+=cnt[i-1];
        for(i=0;i<len1;i++)sa[--cnt[rk[i]]]=i;
        for(k=1;k<=len1;k<<=1){
            for(i=0;i<len1;i++){
                j=sa[i]-k;
                if(j<0)j+=len1;
                tmp[cnt[rk[j]]++]=j;
            }
            sa[tmp[cnt[0]=0]]=j=0;
            for(i=1;i<len1;i++){
                if(rk[tmp[i]]!=rk[tmp[i-1]]||rk[tmp[i]+k]!=rk[tmp[i-1]+k])cnt[++j]=i;
                sa[tmp[i]]=j;
            }
            memcpy(rk,sa,len1*sizeof(int));
            memcpy(sa,tmp,len1*sizeof(int));
            if(j>=len1-1)break;
        }
        for(j=rk[height[i=k=0]=0];i<len1-1;i++,k++){
            while(~k&&s[i]!=s[sa[j-1]+k])height[j]=k--,j=rk[sa[j]+1];
        }
    }
    inline void build()
    {
        int i,j;
        for(i=1;i<=len;i++)f[0][i]=height[i];
        for(j=1;j<15;j++){
            for(i=1;i+(1<<j-1)<=n;i++){
                f[j][i]=min(f[j-1][i],f[j-1][i+(1<<j-1)]);
            }
        }
    }
    inline int ask(int x,int y)
    {
        int k=Log[y-x+1];
        return min(f[k][x],f[k][y-(1<<k)+1]);
    }
    inline int lcp(int x,int y)
    {
        x=rk[x],y=rk[y];
        if(x>y)swap(x,y);
        return ask(x+1,y);
    }
}A,B;

inline int lcp(int x,int y){return A.lcp(x-1,y-1);}
inline int lcs(int x,int y){return B.lcp(n-x,n-y);}
int main()
{
    init_suffix();
    scanf("%d",&T);
    while(T--){
        scanf("%s",s);
        n=strlen(s);
        A.len=B.len=n;
        A.init();B.init();
        for(int i=0;i<n;i++)A.s[i]=B.s[n-i-1]=s[i];
        A.suffix(128);
        A.build();
        B.suffix(128);
        B.build();
        for(int i=1;i<=n;i++)f[i]=g[i]=0;
        for(int i=1;i+i<=n;i++){
            for(int j=i+i;j<=n;j+=i){
                if(s[j-1]==s[j-i-1]){
                    l=j-lcs(j,j-i)+1,r=j+lcp(j,j-i)-1;
                    l=max(l+i-1,j),r=min(r,j+i-1);
                    if(l<=r){
                        f[l]++,f[r+1]--;
                        g[l-i-i+1]++,g[r+1-i-i+1]--;
                    }
                }
            }
        }
        for(int i=1;i<=n;i++)f[i]+=f[i-1],g[i]+=g[i-1];
        ans=0;
        for(int i=1;i<n;i++)ans+=f[i]*g[i+1];
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lalalatianlalu/p/9464231.html
今日推荐