HUST 1352 求重复次数不小于k的子串的个数。

M - M
Time Limit:20000MS    Memory Limit:131072KB    64bit IO Format:%lld & %llu
Appoint description:

Description

The “repetitions” of a string S(whose length is n) is a maximum number “k” such that:
1) k is a factor of n
2) S[0..n/k-1] = S[p*(n/k)..(p+1)*(n/k)-1] for all that (1 <= p < n/k)
for example:
the repetitions of “aaaaaa”is 6.
the repetitions of “abababab”is 4.
the repetitions of “abcdef”is 1.
Now, given a string S and a number K, please tell me how many substrings of S have repetitions NOT less than K.

Input

The input consists of several instances, each one for a single line.
S K
S is a string, K is a number. Check the Description for their meanings.
S contains lowercase letters(ie ‘a‘..‘z‘) only.
1 <= length of S <= 100000.
1 <= K <= length of S.

Output

For each instance, output the number of substring whose repetitions is NOT less than K.

Sample Input

abcabc 2
acmac 3

Sample Output

1
0


题意:输入字符串,k,求重复次数不小于k的子串的个数。

解题思路:枚举字串长度,遍历所有的串,根据lcp向前扩展,更新答案。

代码:

/* ***********************************************
Author :xianxingwuguan
Created Time :2014-1-29 20:43:51
File Name :4.cpp
************************************************ */

#pragma comment(linker, "/STACK:102400000,102400000")
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
const int maxn=300300;
int height[maxn],sa[maxn],rank[maxn],c[maxn],t1[maxn],t2[maxn];  
void da(int *str,int n,int m)  
{  
      int i,j,k,p,*x=t1,*y=t2;  
      for(i=0;i<m;i++)c[i]=0;  
      for(i=0;i<n;i++)c[x[i]=str[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(k=1;k<=n;k<<=1)  
      {  
         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]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;  
         if(p>=n)break;  
         m=p;  
      }  
}  
void calheight(int *str,int n)  
{  
      int i,j,k=0;  
      for(i=0;i<=n;i++)rank[sa[i]]=i;  
      for(i=0;i<n;i++)  
      {  
         if(k)k--;  
         j=sa[rank[i]-1];  
         while(str[i+k]==str[j+k])k++;  
         height[rank[i]]=k;  
      }  
         // printf("sa:");for(i=0;i<=n;i++)printf("%d ",sa[i]);puts("");  
         // printf("rank:");for(i=0;i<=n;i++)printf("%d ",rank[i]);puts("");  
         // printf("height:");for(i=0;i<=n;i++)printf("%d ",height[i]);puts("");  
      
}  
int str[maxn];  
char ss[maxn];  
int Log[maxn];  
int best[23][maxn];  
void init(int n)  
{  
      int i,j;  
      Log[0]=-1;  
      for(i=1;i<=n;i++)  
         Log[i]=(i&(i-1))?Log[i-1]:Log[i-1]+1;  
      for(i=1;i<=n;i++)best[0][i]=height[i];  
      for(i=1;i<=Log[n];i++)  
         for(j=1;j<=n;j++)  
            best[i][j]=min(best[i-1][j],best[i-1][j+(1<<(i-1))]);  
}  
int lcp(int a,int b)  
{  
      a=rank[a];  
      b=rank[b];  
      if(a>b)swap(a,b);  
      a++;  
      int t=Log[b-a+1];  
      return min(best[t][a],best[t][b-(1<<t)+1]);  
}  
int rep[maxn];
int main()
{
      //freopen("data.in","r",stdin);
      //freopen("data.out","w",stdout);
      int i,j,k,m,n,p;
      while(~scanf("%s%d",&ss,&k))
      {
	     n=strlen(ss);
           if(k==1)
	     {
		    printf("%lld\n",(long long)n*(n+1)/2);
		    continue;
	     }
	     for(i=0;i<n;i++)str[i]=ss[i];
	     str[n]=0;
	     da(str,n+1,300);
	     calheight(str,n);
	     init(n);
	     for(i=0;i<=n;i++)rep[i]=1;
	     for(int L=1;L*k<=n;L++)
	     {
		    for(i=0;i<n;i+=L)
		    {
			   int t=lcp(i,i+L);
			   if(!t)continue;
			   j=0;
			   while(j<=i&&j<L&&str[i-j]==str[i-j+L])
			   {
				  if(t>=L&&lcp(i-j,i-j+L)>=(k-1)*L)
					 rep[i-j]=max(rep[i-j],t/L+1);
				  j++;t++;
			   }
		    }
	     }
	     int ans=0;
	     for(i=0;i<=n;i++)if(rep[i]>=k)ans+=rep[i]-k+1;
	     printf("%d\n",ans);
      }
      return 0;
}




HUST 1352 求重复次数不小于k的子串的个数。

上一篇:HUST 1328求每一个前缀在串中出现次数和


下一篇:uva 348 - Optimal Array Multiplication Sequence