Prefixes and Suffixes CodeForces - 432D (KMP的next数组的应用)(图解)

Prefixes and Suffixes

 CodeForces - 432D 

You have a string s = s1s2...s|s|, where |s| is the length of string s, and si its i-th character.

Let's introduce several definitions:

  • A substring s[i..j] (1 ≤ i ≤ j ≤ |s|) of string s is string sisi + 1...sj.
  • The prefix of string s of length l (1 ≤ l ≤ |s|) is string s[1..l].
  • The suffix of string s of length l (1 ≤ l ≤ |s|) is string s[|s| - l + 1..|s|].

Your task is, for any prefix of string s which matches a suffix of string s, print the number of times it occurs in string s as a substring.

Input

The single line contains a sequence of characters s1s2...s|s| (1 ≤ |s| ≤ 105) — string s. The string only consists of uppercase English letters.

Output

In the first line, print integer k (0 ≤ k ≤ |s|) — the number of prefixes that match a suffix of string s. Next print k lines, in each line print two integers lici. Numbers li ci mean that the prefix of the length li matches the suffix of length li and occurs in string s as a substring ci times. Print pairs li ci in the order of increasing li.

Examples

Input

ABACABA

Output

3
1 4
3 2
7 1

Input

AAA

Output

3
1 3
2 2
3 1

题目大意:

给出一个字符串“对于字符串s中与后缀匹配的前缀,输出它在字符串s中作为子串的次数。”谷歌翻译的结果,我觉得意思已经很明确了,不作赘述。

思路:

这个题目很容易让我们想到KMP的自匹配。nxt[len]就是最长的那个前后匹配的串,但是我们的问题来了,如何得出长度更短的前后匹配的串呢?

(此时红色的串是前后匹配的)

我们不妨来看看nxt[nxt[len]]我们知道他是原数组中前nxt[len]个元素的数组中前后匹配的串的长度,也就是:

绿色的串

但是考虑到前后的红色部分也是相同的,所以所有的相等的绿色串应该就是

(图中的绿色的串都是相等的)

Amazing!这样首尾就也是相等的了!充分证明了所有的前后相等的子串就是不断地求自己的next。当然,必要性可以简单证明,这里就不赘述。

至于子串在自身中的重复次数,只需要对每个位置i的next[i]的数量(以next结尾的字符串的数量)的都加上他们自身的数量即可。

具体见代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define endl '\n'
#define sc(x) scanf("%d",&x)

using namespace std;
const int size=1e5+5;
int nxt[size];
char s[size];
int num[size],ans[size];
int mny[size];
int cnt=0;
int m;
void getnext()
{
	int i,j;
    nxt[0] = j = -1;
    i = 0;
    while(i < m)
    {
        while(j!=-1&&s[j]!=s[i])
            j = nxt[j];
        nxt[++i] = ++j; 
    }
}
void query()
{
	cnt=0;
	fill(num,num+m+1,1);
	for(int i=m;i>=1;i--)
	{
		if(nxt[i]!=-1)
		num[nxt[i]]+=num[i];
	}
	for(int i=m;i!=0;i=nxt[i])
	{
		ans[cnt]=i;
		mny[cnt]=num[i];
		cnt++;
	}
	//ans[cnt]=0;mny[cnt++]=num[0];
}
int main()
{
	while(cin>>s)
	{
		m=strlen(s);
		getnext();
		query();
		cout<<cnt<<endl;
		for(int i=cnt-1;i>=0;i--)
		{
			printf("%d %d\n",ans[i],mny[i]);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/baiyifeifei/article/details/81665282