[NOI2016] 优秀的拆分

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int N=3e4;
int n,f[N+7],g[N+7];
struct SuffixArray{
    char s[N+7];
    int m,c[N+7],tp[N+7],rk[N+7],sa[N+7];
    int h[N+7],st[N+7][20];
    void csort(){
        for(int i=0;i<=m;i++) c[i]=0;
        for(int i=1;i<=n;i++) c[rk[i]]++;
        for(int i=1;i<=m;i++) c[i]+=c[i-1];
        for(int i=n;i>=1;i--) sa[c[rk[tp[i]]]--]=tp[i];
    }
    void build(){
        memset(c,0,sizeof c);
        memset(tp,0,sizeof tp);
        memset(rk,0,sizeof rk);
        memset(sa,0,sizeof sa);
        memset(h,0,sizeof h);
        memset(st,0,sizeof st);
        for(int i=1;i<=n;i++) rk[i]=s[i],tp[i]=i;
        m=128,csort();
        for(int w=1,p=1,i;p<n;w<<=1,m=p){
            for(p=0,i=n-w+1;i<=n;i++) tp[++p]=i;
            for(i=1;i<=n;i++)if(sa[i]>w) tp[++p]=sa[i]-w;
            csort(),swap(rk,tp),rk[sa[1]]=p=1;
            for(i=2;i<=n;rk[sa[i]]=p,i++)
                if(tp[sa[i]]!=tp[sa[i-1]]||tp[sa[i]+w]!=tp[sa[i-1]+w]) p++;
        }
        for(int i=1,j,k=0;i<=n;h[rk[i++]]=k)
            for(k=k?k-1:k,j=sa[rk[i]-1];s[i+k]==s[j+k];k++);
        for(int i=1;i<=n;i++) st[i][0]=h[i];
        for(int w=1;w<=18;w++)
            for(int i=1;i+(1<<w)-1<=n;i++)
                st[i][w]=min(st[i][w-1],st[i+(1<<(w-1))][w-1]);
    }
    int Lcp(int a,int b){
        int l=rk[a],r=rk[b];
        if(l>r) swap(l,r); l++;
        int k=log2(r-l+1);
        return min(st[l][k],st[r-(1<<k)+1][k]);
    }
}a,b;

void KonnyWen(){
    memset(f,0,sizeof f);
    memset(g,0,sizeof g);
    scanf("%s",&a.s[1]),n=strlen(&a.s[1]);
    for(int i=1;i<=n;i++) b.s[i]=a.s[n+1-i];
    a.build(),b.build();
    for(int i=1;i<=n;i++) f[i]=g[i]=0;
    for(int w=1;w<=(n>>1);w++)
        for(int i=w;i<=n;i+=w){
            int l=i,r=i+w;
            int lcp=min(w,a.Lcp(l,r));
            int lcs=min(w-1,b.Lcp(n-(l-1)+1,n-(r-1)+1));
            if(lcp+lcs>=w){
                int cov=lcp+lcs-w+1;
                f[r+lcp-cov]++,f[r+lcp]--;
                g[l-lcs]++,g[l-lcs+cov]--;
            }
        }
    for(int i=1;i<=n;i++) f[i]+=f[i-1],g[i]+=g[i-1];
    ll ans=0;
    for(int i=1;i<n;i++) ans+=f[i]*g[i+1];
    printf("%lld\n",ans);
}

int main(){
    int t; scanf("%d",&t);
    while(t--) KonnyWen();
    return 0;
}
 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值