题意:
给定一个长度不超过1e5的字符串,
对于每种既是前缀又是后缀的子串,输出该子串出现的次数
解法:
kmp可以计算出所有既是前缀又是后缀的子串长度:
一开始令temp=len,不断temp=nt[temp],中间出现的就是满足条件的长度(kmp问题,这里不详讲)
然后就是计算出每种前缀在串中出现的次数了
可以利用nt数组dp计算出每种前缀在串中出现的次数,转移方程为:dp(nt[i])+=dp(i)
转移方程这么写时因为前缀pre(i)包含前缀pre(nt(i))
需要逆序遍历,因为pre(nt(i))又包含pre(nt(nt(i))),是一个递归关系
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=1e5+5;
int d[maxm];
int nt[maxm];
char s[maxm];
signed main(){
scanf("%s",s+1);
int n=strlen(s+1);
for(int i=2,j=nt[1]=0;i<=n;i++){
while(j&&s[i]!=s[j+1])j=nt[j];
if(s[i]==s[j+1])j++;
nt[i]=j;
}
//存满足条件的前缀位置
stack<int>ans;
int temp=n;
while(temp){
ans.push(temp);
temp=nt[temp];
}
//统计每种前缀在串中出现的次数
for(int i=n;i>=1;i--){
d[i]++;
d[nt[i]]+=d[i];
}
//输出答案
cout<<ans.size()<<endl;
while(!ans.empty()){
cout<<ans.top()<<' '<<d[ans.top()]<<endl;
ans.pop();
}
return 0;
}