首先我们可以想到的是,既然求的是前缀的长度,就意味着一定是从1开始的,那么我们可以直接用下
标表示每一个前缀。但是可能存在几个前缀互相包含的情况,比如:abababa我们可以看见的是aba中包含着ab和aabab中包含着aba, ab和a从上面我们能观察出一个性质来:将原字符串自匹配后,扫描到字符i时,next[i]存的是他的一个最近的子前缀结尾点我们想为什么会这样呢?加入某个结尾为i的前缀包含着结尾为j的前缀,那么就说明,由前缀j在扩展时扩展失败了,那么next[i]就等于j这样我们就能够快速把出现次数累加下去,不过这就意味着我们最后要倒着统计,由较长的前缀逐步累 加到较短前缀上。怎么说呢,抽1 #include2 #define ll long long 3 using namespace std; 4 const int maxn = 1000086; 5 char ch[maxn]; 6 ll n, next_[maxn]; 7 ll cnt[maxn]; 8 9 int main() {10 cin >> ch + 1;11 n = strlen(ch + 1);12 next_[1] = 0;13 for(int i = 2, j = 0; i <= n; ++i) {14 while(j > 0 && ch[i] != ch[j + 1]) j = next_[j];15 if(ch[i] == ch[j + 1]) j++;16 next_[i] = j;17 }18 for(int i = n; i >= 1; --i) {19 cnt[i] += 1;20 cnt[next_[i]] += cnt[i];21 }22 ll ans = -1000;23 for(int i = 1; i <= n; ++i)24 ans = max(ans, cnt[i] * i);25 cout << ans << '\n';26 return 0;27 }
象脑洞理解一下就好,我口胡的不清楚=-=