uva10829 - L-Gap Substrings 后缀数组+RMQ

Problem J
L-Gap Substrings
Input:
StandardInput

Output: Standard Output

If a string is in the form UVU, where Uis not empty, and V has exactly L characters, we say UVUis an L-Gap string. For example, abcbabc is a 1-Gapstring. xyxyxyxyxy is both a 2-Gap string and also a 6-Gapstring, but not a 10-Gap string (because U is non-empty).

Given a string s, and a positiveinteger g, you are to find the number of g-Gap substrings in s.s contains lower-case letters only, and has at most 50,000characters.

 

Input

Thefirst line contains a single integer t(1<=t<=10), the number oftest cases. Each of the t followings contains an integer g(1<=g<=10)followed bya string s.

 

Output

For each test case, print thecase number and the number of g-Gapsubstrings. Look at the output for sample input for details.

 

Sample Input                               Output for Sample Input

2
1 bbaabaaaaa
5 abxxxxxab
 
Case 1: 7
Case 2: 1

 

  给出L和一个串,输出格式为UVU的有多少个,V的长度为L。

  做法和POJ3693类似。枚举U的长度i和UVU这个串的起始位置j,起始位置不是一个一个枚举,而是0,i,2*i...这样枚举。RMQ求出j和j+i+L位置的LCP,从j-L+1...j这一段处理方法是倒着求j-1和j+i+L-1的LCP(先把整个串在后面倒着复制一遍就是正着求对应位置的)。设sum=min(RMQ(sa.rank[j],sa.rank[j+i+L]),i)+min(RMQ(sa.rank[sa.n-j-1],sa.rank[sa.n-j-i-L-1]),i-1),那么以j-L+1...j起始的U长度为i的符合条件的串共有max(0,sum-i+1)个,自己画画就知道了。这样的时间复杂度(n+n/2+n/3...+1),为nlnn.

#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> pii;

const int MAXN=50010*2;
const int MAXNODE=4*MAXN;
const int LOGMAXN=50;

int T,L,d[MAXN][LOGMAXN];
char str[MAXN];

struct SuffixArray{
    int s[MAXN];
    int c[MAXN];
    int sa[MAXN];
    int height[MAXN];
    int rank[MAXN];
    int t[MAXN],t2[MAXN];
    int n;

    void clear(){
        n=0;
        memset(sa,0,sizeof(sa));
    }
    void build_sa(int m){
        int i,*x=t,*y=t2;
        for(i=0;i<m;i++) c[i]=0;
        for(i=0;i<n;i++) c[x[i]=s[i]]++;
        for(i=1;i<m;i++) c[i]+=c[i-1];
        for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
        for(int k=1;k<n;k<<=1){
            int p=0;
            for(i=n-k;i<n;i++) y[p++]=i;
            for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
            for(i=0;i<m;i++) c[i]=0;
            for(i=0;i<n;i++) c[x[y[i]]]++;
            for(i=1;i<m;i++) c[i]+=c[i-1];
            for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
            swap(x,y);
            p=1;
            x[sa[0]]=0;
            for(i=1;i<n;i++) x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
            if(p>=n) break;
            m=p;
        }
    }
    void build_height(){
        int k=0;
        for(int i=0;i<n;i++) rank[sa[i]]=i;
        height[0]=0;
        for(int i=0;i<n-1;i++){
            if(k) k--;
            int j=sa[rank[i]-1];
            while(s[i+k]==s[j+k]) k++;
            height[rank[i]]=k;
        }
    }
}sa;

void RMQ_init(){
    for(int i=0;i<sa.n;i++) d[i][0]=sa.height[i];
    for(int j=1;(1<<j)<=sa.n;j++)
        for(int i=0;i+(1<<j)<=sa.n;i++) d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]);
}

int RMQ(int L,int R){
    if(L>=R) swap(L,R);
    L++;
    int k=0;
    while((1<<(k+1))<=R-L+1) k++;
    return min(d[L][k],d[R-(1<<k)+1][k]);
}

void solve(int len){
    int ans=0;
    for(int i=1;i<=len/2;i++)
        for(int j=0;j<len;j+=i){
            int sum=0;
            if(j+i+L<len) sum=min(RMQ(sa.rank[j],sa.rank[j+i+L]),i);
            if(sa.n-j-i-L-1>=0) sum+=min(RMQ(sa.rank[sa.n-j-1],sa.rank[sa.n-j-i-L-1]),i-1);
            ans+=max(0,sum-i+1);
        }
    printf("%d\n",ans);
}

int main(){
    freopen("in.txt","r",stdin);
    int cas=0;
    scanf("%d",&T);
    while(T--){
        scanf("%d%s",&L,str);
        sa.clear();
        int len=strlen(str);
        for(int i=0;i<len;i++) sa.s[sa.n++]=str[i]-'a'+1;
        sa.s[sa.n++]=27;
        for(int i=len-1;i>=0;i--) sa.s[sa.n++]=str[i]-'a'+1;
        sa.s[sa.n++]=0;
        sa.build_sa(30);
        sa.build_height();
        RMQ_init();
        //for(int i=0;i<sa.n;i++) printf("i=%d %d\n",i,sa.height[i]);
        printf("Case %d: ",++cas);
        solve(len);
    }
    return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值