码迷,mamicode.com
首页 > 其他好文 > 详细

1511: [POI2006]OKR-Periods of Words

时间:2018-07-22 18:44:35      阅读:159      评论:0      收藏:0      [点我收藏+]

标签:ble   ==   ret   kmp   poi   字符   target   getc   ons   

1511: [POI2006]OKR-Periods of Words

https://www.lydsy.com/JudgeOnline/problem.php?id=1511

 

题意:

  对于一个串的所有前缀,设为s,求出它的最大前缀Q,使得s为QQ的前缀。求最大前缀长度的和。

分析:

  KMP+next数组。

  next数组表示的是这个字符串的最大的公共前缀后缀。对于字符串s,设其next为j,那么它的前j个和后j个是相等的。如果这j个没有重叠,那么所求的最长前缀就是1~n-j。把这个前缀重复两遍可以包含s。所求的就是最小的这样border,最小的j(j越小,相当于n个字符,后j个更少,那么剩余的所求的前缀就越长了)。然后求出最小的公共前后缀。

 

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 
 5 inline int read() {
 6     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch==-)f=-1;
 7     for (;isdigit(ch);ch=getchar())x=x*10+ch-0;return x*f;
 8 }
 9 
10 const int N = 1000100;
11 
12 char A[N];
13 int p[N];
14 
15 int main() {
16     int n; cin >> n;
17     scanf("%s",A+1);
18     p[1] = 0;
19     for (int i=2; i<=n; ++i) {
20         int j = p[i-1];
21         while (j && A[i]!=A[j+1]) j = p[j];
22         if (A[i] == A[j+1]) j++;
23         p[i] = j;
24     }
25     LL ans = 0;
26     for (int i=1; i<=n; ++i) {
27         int j = i;
28         while (p[j]) j = p[j]; // 这里看到这样写的p[p[j]],其实每个p[i]在下面已经更新了,不需要跳很多次。 
29         if (p[i] != 0) p[i] = j; // 类似于记忆化,前缀i的跳的最优位置。 
30         ans += i - j; 
31     }
32     cout << ans;
33     return 0;
34 }

 

1511: [POI2006]OKR-Periods of Words

标签:ble   ==   ret   kmp   poi   字符   target   getc   ons   

原文地址:https://www.cnblogs.com/mjtcn/p/9350964.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!