51nod 1277 KMP 前缀出现次数

51NOD 1277:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1277

跟HDU 6153还挺像的:http://www.cnblogs.com/Egoist-/p/7435573.html

相比与上面那个题,这个还要相对简单一些,只需要处理模式串自己就好了。

一开始写麻烦了,直接套了HDU6153的代码,后来发现……他就是个模式串本身的匹配,我干嘛弄那么麻烦Orz

题意:找前缀长度*出现次数的最大值,长度好说,问题就在于求出现次数了

最容易得到的前缀的长度和出现次数是模式串本身,也就是(len,1)(长度,出现次数);

而在处理next[i]时,长度为i的前缀至少出现一次,那么我们用num[i]记录前缀[0……i]的出现次数,全部填充为1;

与HDU6153一样,在计数前缀i的出现次数时,由于kmp减少回溯次数的特性,省略了相同前缀的计数,

但是由于处理的是前缀,[0,next[i]]出现的前缀,在[0,i]中必然出现,倒序,num[next[i]]+num[i]即可;

(至于为什么是倒序,emmmm,有种DP的感觉呢……为了减少next数组处理部分的改写(好吧其实是我懒),

只有模式串本身,长度为len的前缀的出现次数是已知的,num[i]时是由num[i+1...len]得来的)

#include<iostream>
#include<algorithm>
using namespace std;
const int MAX = 100000;
int nextt[MAX + 10];
int num[MAX + 10];
char s[MAX + 10];
int t,len;
void getnext()
{
    int p=0, k = -1;
    nextt[0] = -1;
    while (p < len)
    {
        if (k == -1 || s[p] == s[k])
        {
            p++;k++;
            nextt[p] =k;
         }
        else k = nextt[k];
    }
}
int main()
{
    while (cin >> s)
    {
        len = strlen(s);
        fill(num, num+len+1, 1);
        getnext();
        int maxx = 0;
        for (int i = len; i > 0; i--)
        {
            num[nextt[i]] += num[i];
            maxx = max(maxx, num[i]*i);
        }
        cout << maxx << endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Egoist-/p/7435754.html