Uncle Mao is a wonderful ACMER. One day he met an easy problem, but Uncle Mao was so lazy that he left the problem to you. I hope you can give him a solution.
Given a string s, we define a substring that happens exactly k
Input
The first line contains an integer
T
(
T≤100
) implying the number of test cases.
For each test case, there are two lines:
the first line contains an integer k ( k≥1 ) which is described above;
the second line contain a string s ( length(s)≤105 ).
It's guaranteed that ∑length(s)≤2∗106
.
Output
For each test case, print the number of the important substrings in a line.
Sample Input
Sample Output
Given a string s, we define a substring that happens exactly k
times as an important string, and you need to find out how many substrings which are important strings.
For each test case, there are two lines:
the first line contains an integer k ( k≥1 ) which is described above;
the second line contain a string s ( length(s)≤105 ).
It's guaranteed that ∑length(s)≤2∗106
2 2 abcabc 3 abcabcabcabc
6 9
题意:给你一个数字k,给你一个串,让你求出有多少子串是恰好出现k次的。
思路:后缀数组啊,按照sa【i】的顺序排列一下,然后框定一长度为k的区间,求height数组在这段区间的最小值,最小值一定是满足部分条件的,如果这个长度为k的区间上面的字符串或者下面的字符串有重复,那么需要减去他们之间的最大值。这就是一个区间的贡献。但是注意当k为1的时候单独讨论一下。
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<complex>
#include<queue>
using namespace std;
const int MAXN=1e5+10;
char s[MAXN];
int t1[MAXN],t2[MAXN],cc[MAXN],x[MAXN],sa[MAXN],Rank[MAXN],height[MAXN],Min[MAXN][50],kkk;
int len;
bool cmp(int *y,int a,int b,int k)
{
int a1=y[a];
int b1=y[b];
int a2=a+k>=len ? -1:y[a+k];
int b2=b+k>=len ? -1:y[b+k];
return a1==b1 && a2==b2;
}
int make_sa()
{
int *x=t1,*y=t2;
int m=26;
for(int i=0; i<m; i++) cc[i]=0;
for(int i=0; i<len; i++) ++cc[x[i]=s[i]-'a'];
for(int i=1; i<m; i++) cc[i]+=cc[i-1];
for(int i=len-1; i>=0; i--) sa[--cc[x[i]]]=i;
for(int k=1; k<=len; k<<=1)
{
int p=0;
for(int i=len-k; i<len; i++) y[p++]=i;
for(int i=0; i<len; i++)
if( sa[i]>=k ) y[p++]=sa[i]-k;
for(int i=0; i<m; i++) cc[i]=0;
for(int i=0; i<len; i++) ++cc[x[y[i]]];
for(int i=1; i<m; i++) cc[i]+=cc[i-1];
for(int i=len-1; i>=0; i--) sa[--cc[x[y[i]]]]=y[i];
swap(x,y);
m=1;
x[sa[0]]=0;
for(int i=1; i<len; i++)
x[sa[i]]=cmp(y,sa[i],sa[i-1],k) ? m-1:m++;
if( m>=len ) break;
}
}
void make_height()
{
for(int i=0; i<len; i++) Rank[sa[i]]=i;
height[0]=0;
int k=0;
for(int i=0; i<len; i++)
{
if(!Rank[i]) continue;
int j=sa[Rank[i]-1];
if(k) k--;
while(s[i+k]==s[j+k]) k++;
height[Rank[i]]=k;
}
}
void RMQ()
{
for(int i=0; i<len; i++)
Min[i][0]=height[i];
for(int j=1; j<31; j++)
for(int i=0; i<len; i++)
{
if(i+(1<<j)-1<len)
{
Min[i][j]=min(Min[i][j-1],Min[i+(1<<(j-1))][j-1]);
}
}
}
int query(int st,int en)
{
int kk=(int)((log(en-st+1))/log(2.0));
return min(Min[st][kk],Min[en-(1<<kk)+1][kk]);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d %s",&kkk,s);
len=strlen(s);
make_sa();
make_height();
long long sum=0;
RMQ();
height[len]=0;
for(int i=kkk-1; i<len; i++)
{
int x=((i-kkk+2<=i)?query(i-kkk+2,i):(len-sa[i]))-max(height[i+1],height[i-kkk+1]);
if(x>0)
sum+=x;
}
printf("%lld\n",sum);
}
}