1. 程式人生 > >[KMP] BZOJ 1511/POI2006 OKR-period of words

[KMP] BZOJ 1511/POI2006 OKR-period of words

復制 immediate 分享 enc lin scan turn 原來 算法

題目描述

A string is a finite sequence of lower-case (non-capital) letters of the English alphabet. Particularly, it may be an empty sequence, i.e. a sequence of 0 letters. By A=BC we denotes that A is a string obtained by concatenation (joining by writing one immediately after another, i.e. without any space, etc.) of the strings B and C (in this order). A string P is a prefix of the string !, if there is a string B, that A=PB. In other words, prefixes of A are the initial fragments of A. In addition, if P!=A and P is not an empty string, we say, that P is a proper prefix of A.

A string Q is a period of Q, if Q is a proper prefix of A and A is a prefix (not necessarily a proper one) of the string QQ. For example, the strings abab and ababab are both periods of the string abababa. The maximum period of a string A is the longest of its periods or the empty string, if A doesn‘t have any period. For example, the maximum period of ababab is abab. The maximum period of abc is the empty string.

Task Write a programme that:

reads from the standard input the string‘s length and the string itself,calculates the sum of lengths of maximum periods of all its prefixes,writes the result to the standard output.

一個串是有限個小寫字符的序列,特別的,一個空序列也可以是一個串. 一個串P是串A的前綴, 當且僅當存在串B, 使得 A = PB. 如果 P!=A 並且 P 不是一個空串,那麽我們說 P 是A的一個proper前綴. 定義Q 是A的周期, 當且僅當Q是A的一個proper 前綴並且A是QQ的前綴(不一定要是proper前綴). 比如串 abab 和 ababab 都是串abababa的周期. 串A的最大周期就是它最長的一個周期或者是一個空串(當A沒有周期的時候), 比如說, ababab的最大周期是abab. 串abc的最大周期是空串. 給出一個串,求出它所有前綴的最大周期長度之和.。

輸入輸出格式

輸入格式:

In the first line of the standard input there is one integer k \((1\le k\le 1\ 000\ 000)\) - the length of the string. In the following line a sequence of exactly k lower-case letters of the English alphabet is written - the string.

輸出格式:

In the first and only line of the standard output your programme should write an integer - the sum of lengths of maximum periods of all prefixes of the string given in the input.

輸入輸出樣例

輸入樣例#1:

8
babababa

輸出樣例#1:
24

題解

一個字符串A的proper前綴的定義滿足四個條件

  1. 為A的前綴
  2. 不能為空
  3. P!=A
  4. A為PP的前綴,但不一定要是poper前綴
    題目要我們求每個子串最長poper前綴長度之和,那麽我們可以畫一張圖
    技術分享圖片
    我們假設P為A的最長poper前綴,在P復制一遍接在後面後,如需要滿足條件,則A為PP的前綴,可以得出塗黑的一段和下面對應位置上的子串是一樣的,而這一段子串是由P復制而來的,也就是說這一段子串是A的一個前綴,而塗黑的子串為A的一個後綴,如需要P的長度最大,則塗黑部分需最小,也就是求A的最短公共前後綴
    所以我們轉換一下,next[i]表示i-1的最短公共前後綴
    那麽怎麽求它呢?
    我們可以在原來的kmp算法中,依然先求出i的最長公共前後綴,然後不斷向前跳,因為要滿足條件P不為空,所以
while(next[next[i]]) next[i]=next[next[i]]

Code

#include<cstdio>
#include<string>
#include<iostream>
#include<cstring>
#include<cmath>
#define Min(a,b) (a)<(b)?(a):(b)
#define Max(a,b) (a)>(b)?(a):(b)
#define in(i) (i=read())
using namespace std;
int read() {
  int ans=0,f=1; char i=getchar();
  while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
  while(i>='0' && i<='9') {ans=(ans<<1)+(ans<<3)+i-'0'; i=getchar();}
  return ans*f;
}
int ans,n;
int nex[1000010];
char s[1000010];
void get() {
  int p=0;
  for(int i=1;i<n;i++) {
    while(p && s[p]!=s[i]) p=nex[p];
    if(s[p]==s[i]) nex[i+1]=(++p);
    else nex[i+1]=0;
  }
}
void match() {
  for(int i=1;i<=n;i++) {
    while(nex[nex[i]]) nex[i]=nex[nex[i]];
    if(nex[i]) ans+=i-nex[i];
  }
}
int main()
{
  in(n); scanf("%s",s);
  get(); match();
  printf("%d\n",ans);
  return 0;
}

博主蒟蒻,隨意轉載.但必須附上原文鏈接

http://www.cnblogs.com/real-l/

[KMP] BZOJ 1511/POI2006 OKR-period of words