题意:
求一个字符串的所有后缀子串和原串的比较中要比较几次,才能得到最长公共前缀。
题解:扩展KMP裸题,用KMP推了2小时硬是没有弄出来,最后队友问我还有什么比较算法,突然想到还有扩展KMP然后百度了一下就直接过了。(谢队友不杀)听说还有用马拉车过的。。。。
PS:首先,所有的extend[i]+1,因为一个长度为N的串,那么其比较次数必然>=N。所有扩展KMP的extend[i]中,如果可以直接匹配到了后缀串最后一位字符,那么最后的结果不需要+1(因为不需要比较后一项来让其出错)。+1也只是用来最后凑成+N
关于extend的用处,可以百度扩展KMP来研究。
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn = 1e6 + 7;
char str[maxn];
const int MAX = maxn; //字符串长度最大值
int knext[MAX], extend[MAX];
//预处理计算knext数组
void getknext(char str[])
{
int i = 0, j, po, len = strlen(str);
knext[0] = len; //初始化knext[0]
while (str[i] == str[i + 1] && i + 1 < len) i++; knext[1] = i; //计算knext[1]
po = 1; //初始化po的位置
for (i = 2; i < len; i++)
{
if (knext[i - po] + i < knext[po] + po) //第一种情况,可以直接得到knext[i]的值
knext[i] = knext[i - po];
else //第二种情况,要继续匹配才能得到knext[i]的值
{
j = knext[po] + po - i;
if (j < 0) j = 0; //如果i>po+knext[po],则要从头开始匹配
while (i + j < len && str[j] == str[j + i]) j++; knext[i] = j;
po = i; //更新po的位置
}
}
}
//计算extend数组
void EXKMP(char s1[], char s2[])
{
int i = 0, j, po, len = strlen(s1), l2 = strlen(s2);
getknext(s2); //计算子串的knext数组
while (s1[i] == s2[i] && i < l2 && i < len) i++; extend[0] = i;
po = 0; //初始化po的位置
for (i = 1; i < len; i++)
{
if (knext[i - po] + i < extend[po] + po) //第一种情况,直接可以得到extend[i]的值
extend[i] = knext[i - po];
else //第二种情况,要继续匹配才能得到extend[i]的值
{
j = extend[po] + po - i;
if (j < 0) j = 0; //如果i>extend[po]+po则要从头开始匹配
while (i + j < len && j < l2 && s1[j + i] == s2[j]) j++; extend[i] = j;
po = i; //更新po的位置
}
}
}
int main() {
int t;
cin >> t;
while (t--) {
memset(knext, 0, sizeof(knext));
memset(extend, 0, sizeof(extend));
scanf("%s", str);
EXKMP(str, str);
long long sum = 0;
int re = strlen(str);
for (int i = 1; i <= re; i++) {
sum += extend[i];
if ((extend[i] + i) != re)
sum++;
}
cout << sum << endl;
}
return 0;
}