D. Prefixes and Suffixes
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output
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 li ci. 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
Copy
ABACABA
output
Copy
3 1 4 3 2 7 1
input
Copy
AAA
output
Copy
3 1 3 2 2 3 1
做题目呢,一定要自己在草稿纸上写写画画演算一下。
题目大意:给一段字符串,找出前缀与后缀相同的长度,按照其长度从小到达,输出长度及在整个文本串中的出现次数。
通过在纸上胡乱写写画画的分析:Next[n]存储的是除了串本身,最长前缀与后缀相同的那个长度;而下一个能匹配的地方,就是Next[Next[i]]……一直匹配下去直到0,再加上串本身长度,就是所有的相同前缀后缀的长度答案了;kmp的Next数组可以说是很有点儿东西了。
统计出现次数方法:倒着从后往前,记录一个cnt数组,相当于动态规划了。一个子串的出现次数,是它本身长度在Next[]数组中的出现次数,再加上所有包含它的更长的长度,多的这部分如何去算?可以考虑到如果i后面某一位j,Next[j]=i,那么i前的串不是又出现了一次吗;并且这样不会重复计算~
最后输出即可~
#include <cstdio>
#include <cstring>
const int maxs=100020;
char str[maxs];
int Next[maxs];
int cnt[maxs],ans[maxs];
int len;
void get_Next(char* s,int* Next)
{
Next[0]=Next[1]=0;
for(int i=1;i<len;++i){
int j=Next[i];
while(j&&s[i]!=s[j]) j=Next[j];
if(s[i]==s[j]) Next[i+1]=j+1;
else Next[i+1]=0;
}
}
int main()
{
memset(cnt,0,sizeof(cnt));
scanf("%s",str);
len=strlen(str);
get_Next(str,Next);
for(int i=len;i;--i){
cnt[i]+=1;
if(Next[i]){
cnt[Next[i]]+=cnt[i];
}
}
int x=len,j=0;
ans[0]=x;
while(Next[x]){
x=Next[x];
ans[++j]=x;
}
printf("%d\n",j+1);
for(;j>=0;--j){
printf("%d %d\n",ans[j],cnt[ans[j]]);
}
return 0;
}