后缀数组 hdu6661 Acesrc and String Theory

166 篇文章 0 订阅

Problem Description

Acesrc is a famous string theorist at Nanjing University second to none. He insists that we should always say an important thing k times. He also believes that every string that can be obtained by concatenating k copies of some nonempty string is splendid. So, he always teaches newcomers, ``String theory problems are important! String theory problems are important! ... String theory problems are important!"

Today, he wants to examine whether the newcomers remember his instruction. He presents a string consisting of lower case letters and asks them the number of splendid substrings of the presented string. No one can solve this problem, and they will be scolded for hours. Can you help them solve this problem?

Note that equal splendid substrings occurred in different positions should be counted separately.

Input

The first line of input consists of a single integer T (1≤T≤10), denoting the number of test cases. Each test case starts with a single line of an integer k (1≤k≤20). The second line of a test case is a string S consisting of lower case letters only, the length of which is between 1 and 3×105 inclusive. The sum of the lengths of strings in all test cases never exceeds 106.

Outpu

For each test case, print the answer as a single integer in a single line.

Sample Input

3 2 aabb

2 abababab

3 abc

Sample Output

2

6

0

 

Source

2019 Multi-University Training Contest 8

 

这个题和poj3693一样,但是数据没有3693水,所以匹配前后缀以及在划分段的时候,要注意一下。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int M=1e6+50;
int Log[M],K;
long long res;
struct Node{
    int n,m,rk[M],height[M],c[M],sa[M],x[M],y[M],t[M][35];
    char s[M];
    void getsa(){
        for(int i=0;i<=m;i++) c[i]=0;
        for (int i=1; i<=n; ++i) ++c[x[i]=s[i]-'a'+1];
        for (int i=2; i<=m; ++i) c[i]+=c[i-1];
        for (int i=n; i>=1; --i) sa[c[x[i]]--]=i;
        for (int k=1; k<=n; k<<=1) {
            int num=0;
            for (int i=n-k+1; i<=n; ++i) y[++num]=i;
            for (int i=1; i<=n; ++i) if (sa[i]>k) y[++num]=sa[i]-k;
            for (int i=1; i<=m; ++i) c[i]=0;
            for (int i=1; i<=n; ++i) ++c[x[i]];
            for (int i=2; i<=m; ++i) c[i]+=c[i-1];
            for (int i=n; i>=1; --i) sa[c[x[y[i]]]--]=y[i],y[i]=0;
            swap(x,y);
            x[sa[1]]=1;
            num=1;
            for (int i=2; i<=n; ++i)
                if((y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]))x[sa[i]]=num;
                else x[sa[i]]=++num;
            if (num==n) break;
            m=num;
        }
        int k=0;
        for (int i=1; i<=n; ++i) rk[sa[i]]=i;
        for (int i=1; i<=n; ++i) {
            if (rk[i]==1) continue;//第一名height为0
            if (k) --k;//h[i]>=h[i-1]-1;
            int j=sa[rk[i]-1];
            while (j+k<=n && i+k<=n && s[i+k]==s[j+k]) ++k;
            height[rk[i]]=k;
        }
    }
    void rmq(){
        for(int i=1;i<=n;i++)t[i][0]=height[i];
        for(int j=1;(1<<j)<=n;j++)
            for(int i=1;i+(1<<j)-1<=n;i++)
                t[i][j]=min(t[i][j-1],t[i+(1<<(j-1))][j-1]);
    }
    int ask(int l,int r){
        l=rk[l],r=rk[r];
        if(l>r)swap(l,r);
        l++;if(l>r)return 0;
        int tt=Log[r-l+1];
        return min(t[l][tt],t[r-(1<<tt)+1][tt]);
    }
}A,B;
void work(int l,int r,int j){
    int pre=B.ask(A.n-r+1,A.n-l+2),las=A.ask(l,r+1);
    l-=pre;r+=las;
    res+=max(0,r-l+1-K*j+1);
}
int main(){
    Log[1]=0;
    for(int i=2;i<M;i++)Log[i]=Log[i>>1]+1;
    int T;scanf("%d",&T);
    while(T--){
        scanf("%d",&K);
        scanf("%s",A.s+1);
        A.n=strlen(A.s+1);A.m=30;
        if(K==1){
            res=A.n;
            printf("%lld\n",res*(res+1)/2);
            continue;
        }else res=0;


        for(int i=1;i<=A.n;i++) B.s[A.n-i+1]=A.s[i];
        B.s[A.n+1]=0;
        B.n=A.n;
        B.m=A.m;
        A.getsa();B.getsa();
        A.rmq();B.rmq();
//        for(int i=1;i<=A.n;i++)cout<<A.sa[i]<<" ";cout<<endl;
        for(int j=1;j<=A.n/2;j++){
            int las=1;
            for(int i=j+1;i<=A.n;i+=j){
                if(A.ask(las,i)>=j)continue;
                work(las,i-1,j);
                if(i+j-1<=A.n)las=i;
                else las=0;
            }
            if(las)work(las,A.n,j);
        }
        printf("%lld\n",res);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值