common

C: COMMON PALINDROMES
原案・解説:保坂
問題概要
• 文字列 S, T の共通の回文を数える
• ただしある回文が S に a 回,T に b 回現れていたら ab
個として数える
• |S|, |T| <= 50,000
解法 (1)
• Suffix Array を使う
• 接尾辞をソートした配列
•
•
•
•
例: "ICPC" の Suffix Array は [ "C", "CPC", "ICPC", "PC" ]
実用的には O(N (log N)2) で構築できる (N は文字列の長さ)
隣接 2 項の最長共通接頭辞を O(N) で求められる
さらに RMQ を用いて任意の 2 項の最長共通接頭辞を求められる
• 構築 O(N log N) / クエリ O(1)
• 構築 O(N) / クエリ O(log N)
• 文字列 S $1 rev(S) $2 T $3 rev(T) に対して Suffix Array を
構築する
• $1, $2, $3 は区切りのための番号が小さな文字
解法 (1)
• 例: ICPC $1 CPCI $2 CPCPC $3 CPCPC
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
S
T
T'
S'
S
T
T'
S'
T
T'
S'
S
S
T
T'
S'
T
T'
C
C
C
CI
CPC
CPC
CPC
CPCI
CPCPC
CPCPC
I
ICPC
PC
PC
PC
PCI
PCPC
PCPC
1
1
1
1
3
3
3
3
5
0
1
0
2
2
2
2
4
解法 (1)
• 長さが奇数 2k - 1の回文について考える
• 長さ偶数のものも同様
• k の大きい順に考えることにする
• 例: S = "...AABACDCABAB...",k = 4
• Suffix Array 中には,S の接尾辞 "DCAB..." と rev(S) の接尾辞
"DCAB..." として現れる (これらはどちらも回文の中心から始
まっている)
• すなわち,共通接頭辞が k の部分をグループにしておくと,同じ
グループ内に現れる
解法 (1)
• 最長共通接頭辞が k 以上のものをグループにまとめてい
く
• 文字列中の各位置に対して,そこから順方向のものと逆
方向のものが同じグループに入るのがいつかを求めてお
く
• 先ほどの例なら "DCABAB..." と "DCABAA..." が同じグループに
入るのは k = 5 のとき
• すなわち,ある位置を中心とする最長の回文のサイズに対応
• Suffix Array 上で 2 項の最長共通接頭辞を求めればよい
• k が小さくなり条件を満たしたらグループのカウンタを
増やす
解法 (1)
• 管理するもの
• グループごとに,
• S と rev(S) で同じ位置から始まるものの個数 a
• T と rev(T) で同じ位置から始まるものの個数 b
• 積 ab のすべてのグループについての和 X
• ある k の値に対して処理するごとに,X を答えに足す
• (a1, b1), (a2, b2) のグループをまとめるときは,X から
a1b1 + a2b2 を減らし (a1 + a2)(b1 + b2) を増やす
• (a, b) のグループに S のカウンタを増やすときは,X か
ら ab を減らし (a +1)b を増やす
解法 (1)
• 計算量
•
•
•
•
N = |S| + |T|
Suffix Array の構築 O(N2 (log N)2)
RMQ の処理 O(N log N)
長いほうから X を更新していく O(N) くらい (Union-Find を使え
ば少し増える)
• 各ステップがんばれば O(N) !
• もちろん定数が重いです
解法 (2)
• 概略:短い回文と長い回文にわける
• 境目は √N 程度
• 短い回文は各中心の位置から作る
• 長い回文は「あまりない」のでうまく処理できる
• それぞれの文字列に対して回文とその個数をすべて求め,適
切なハッシュを作って答えを求める
• 32 bit 整数のハッシュを使うと誕生日攻撃で間違いなく衝突します
• O(N √N log N)
参考
• 「各位置を中心とする最大の回文の長さ」は Suffix
Array を使わなくても O(N) で比較的シンプルに求めら
れる
• Manacher のアルゴリズム
• 一部の処理が楽になります
• N 文字の文字列中に現れる回文は高々 N 種類
• 頭の体操になるので知らなかった方は証明を考えてみましょう
• これを使うと簡単な解法になるかも?
結果
•
•
•
•
•
正解 / 提出: 1 / 16
提出チーム: 6
正解チーム: 1
最初の提出: redsign (00:44)
最初の正解: __________ (03:34)