1511: [POI2006]OKR-Periods of Words
阿新 • • 發佈:2018-07-22
style pro spa 最優 scanf read long 包含 pre
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