POJ2406 Power Strings POJ1961 Period
阿新 • • 發佈:2020-07-17
http://poj.org/problem?id=2406
http://poj.org/problem?id=1961
幾乎是一個題
1961是對於第 \(i\) 位,求 \([1,i]\) 能不能由一段字元迴圈一次以上組成,輸出 \(i\) 和這樣的長度最小的迴圈節迴圈次數
2406是隻對第 \(n\) 位輸出最小長度迴圈節迴圈次數
kmp,考慮 kmp 的 \(fail\) 陣列,\(fail_i\) 表示的是如果 \(i\) 失配,那麼要從哪一位開始繼續匹配
更本質的,他是 \([1,i]\) 中,最長的字首等於字尾的長度
例如 \(fail_i=m\),那麼字串 \([1,m]=[i-m+1,i]\)
因為並集等於整個區間,所以 \(\forall 1\le j \le fail_i,s(j)=s(j+i-fail_i)\)
對於這個式子也可以理解為字首向後移動了 \(i-fail_i\) 位得到了字尾,所以相當於每一個區間內字元都與向後移動 \(i-fail_i\) 位的字元相同
因此,只要 \(i \bmod i-fail_i=0\),就說明了 \(i-fail_i\) 是 \([1,i]\) 最小迴圈節長度(這也是為什麼剛才說可能)
POJ2406
char s[6000005]; int fail[6000005]; int main(){ scanf("%s",s+1); while(s[1]!='.'){ int n=std::strlen(s+1); fail[1]=0; for(reg int j,i=2;i<=n;i++){ j=fail[i-1]; while(j&&s[j+1]!=s[i]) j=fail[j]; if(j) fail[i]=j+1; else fail[i]=(s[1]==s[i]); } printf("%d\n",(n%(n-fail[n]))?1:(n/(n-fail[n]))); scanf("%s",s+1); } return 0; }
POJ1961
char s[6000005]; int fail[6000005]; int n; int main(){ scanf("%d",&n); int T=0; while(n){ scanf("%s",s+1); fail[1]=0; for(reg int j,i=2;i<=n;i++){ j=fail[i-1]; while(j&&s[j+1]!=s[i]) j=fail[j]; if(j) fail[i]=j+1; else fail[i]=(s[1]==s[i]); } printf("Test case #%d\n",++T); for(reg int i=2;i<=n;i++) if(!(i%(i-fail[i]))&&i/(i-fail[i])>1) printf("%d %d\n",i,i/(i-fail[i])); EN; scanf("%d",&n); } return 0; }