题目链接:https://codeforces.com/problemset/problem/432/D
题目大意:问前缀和后缀相同的字符串位置和在字符串中出现的次数
题目思路:一种是先用拓展KMP,然后位置加上next数组正好是len的就是符合要求的,还有一种是直接用kmp往回跳,也是符合要求的,然后就是可以发现一个性质,就是如果从后往前,所有人都把自己的num给前一个next的人,那么最后位置上得到的num就是次数,可以通过举样例证明这一点,理解也比较容易。
以下是代码:
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(ll i=a;i<=b;i++)
#define per(i,a,b) for(ll i=a;i>=b;i--)
#define ll long long
const ll MAXN = 1e5+5;
const ll MOD = 1e9+7;
ll q,nxt[MAXN],extend[MAXN];
string s,t;
void getnxt()
{
nxt[0]=t.size();//nxt[0]一定是T的长度
ll now=0;
while(t[now]==t[1+now]&&now+1<(int)t.size())now++;//这就是从1开始暴力
nxt[1]=now;
ll p0=1;
for(ll i=2;i<(int)t.size();i++)
{
if(i+nxt[i-p0]<nxt[p0]+p0)nxt[i]=nxt[i-p0];//第一种情况
else
{//第二种情况
ll now=nxt[p0]+p0-i;
now=max(now,0ll);//这里是为了防止i>p的情况
while(t[now]==t[i+now]&&i+now<(int)t.size())now++;//暴力
nxt[i]=now;
p0=i;//更新p0
}
}
}
ll pos;
ll p[MAXN],Next[MAXN];
void getnext()//获取next数组
{//记住当不匹配的时候 我们要找的是上一次完成匹配的情况下的最大匹配值
// 目的: 这样就不用把i回溯来匹配了,所以next的存储方式就出来了
ll i,n,k;
n=t.size();
k=-1;
Next[0]=-1;
i=0;
while(i<n)
{
if(k==-1 || t[i]==t[k])// k=-1用于指针i的移动 结合k=next[k]看
{
i++;
k++;
Next[i]=k;//为什么在i处能找到最大前后缀而存在i+1处?
} //对于ab串 我在j处与i不匹配 你说我是找j处的最大前后缀 还是 j-1 ?
//拜托 如果找j处的就和前面条件(找已完成匹配(a与b)的最大数内的
//最长前后缀(b自身))矛盾了
//所以我把它存在 i+1处 而不是i处 你反过来站在j处看自身保存的是什么就明白了
else k=Next[k];//把这一步看成是 值的暂时存储
//至于为什么存next[k] 这个和上面j保存 j-1的情形一样
}
}
ll ans[MAXN];
int main(){
while(cin>>t){
pos=0;
getnxt();
getnext();
ll len=t.size();
per(i,len-1,0){
//cout<<nxt[i]<<endl;
if(nxt[i]+i==len){
p[++pos]=len-i;
}
}
rep(i,1,len)ans[i]=1;
per(i,len,1){
ans[Next[i]]+=ans[i];
}
cout<<pos<<endl;
rep(i,1,pos){
cout<<p[i]<<" "<<ans[p[i]]<<endl;
}
}
return 0;
}