# ARC181 - B Annoying String Problem diff: 1633 https://atcoder.jp/contests/arc181/tasks/arc181_b ## 解法 明らかに$|f(S, T, X)| = |f(S, T, Y)|$が必要である。この等式を考えると$T$の長さを特定することができる。 - $|T|$の長さが非負整数でないならば即座にNoと分かる - $\text{cnt}_{1}(X) = \text{cnt}_{1}(Y)$のときはコーナーケースだけど、このときの判定問題は自明 <br /> $|T|$は最大 $(5\times 10^{5})^{2}$程度になり得ることに注意。めっちゃでかい。 - $X = 0000000...., Y = 1$のときとか <br /> 一般性を失わず$X_{1} = 0, Y_{1} = 1$を仮定する。 1. $|S| \ge |T|$のとき、$T$は$S$の長さ$|T|$の接頭辞になる 1. $|S| \lt |T|$のとき、$T$の始め$|S|$文字は$S$と一致しなければならない。$|S| + 1$文字目以降に関しては$X_{2}, X_{3}, \dots$によって定まる。 2. $X_{2} = 1$ならば、$i\equiv j\pmod{|S|}\rightarrow T_{i} = T_{j}$が必要となり、$T$は$S$の繰り返し文字列になることがわかる 3. $X_{2} = 0$ならば、$T_{|S| + 1}, \dots T_{2|S|}$も$S$と一致する必要がある。$X_{3}$に関して同じ議論を進めることになる 結局の所$T$は$T_{i} = S_{i\mod{|S|}}$が成り立つ必要がある。すなわち$T$は$S$の繰り返し文字列になる。 $T$ が一意に定まった。しかも $S$のローリングハッシュが計算済と仮定すると $T$のローリングハッシュも$O(|X| + |Y|)$で計算することが可能である。 以上より、$f(S, T, X)$と$f(S, T, Y)$のローリングハッシュが計算できた。 ## 実装 ```cpp= #include <bits/stdc++.h> #include "Src/Algebra/Monoid/RollingHashMonoid.hpp" using namespace zawa; using Monoid = RollingHashMonoid; using E = Monoid::Element; using V = E::Value; V E::base{ E::randomValue(26) }; E f(E S, E T, const std::string& X) { E res{}; for (auto c : X) { res = Monoid::operation(res, c == '0' ? S : T); } return res; } bool solve() { std::string S, X, Y; std::cin >> S >> X >> Y; int a{(int)std::count(X.begin(), X.end(), '0')}; int b{(int)std::count(X.begin(), X.end(), '1')}; int c{(int)std::count(Y.begin(), Y.end(), '0')}; int d{(int)std::count(Y.begin(), Y.end(), '1')}; if (b == d) return a == c; if ((long long)(S.size() * (a - c)) % (d - b)) return false; long long len{(long long)S.size() * (a - c) / (d - b)}; if (len < 0) return false; E prodS{}; for (auto c : S) prodS = Monoid::operation(prodS, E{c}); E prodT{}; while (len >= (int)S.size()) { prodT = Monoid::operation(prodT, prodS); len -= (int)S.size(); } for (int i{} ; i < len ; i++) { prodT = Monoid::operation(prodT, E{S[i]}); } return f(prodS, prodT, X) == f(prodS, prodT, Y); } int main() { std::cin.tie(nullptr)->sync_with_stdio(false); int T; std::cin >> T; while (T--) { std::cout << (solve() ? "Yes" : "No") << '\n'; } } ``` 提出リンク: https://atcoder.jp/contests/arc181/submissions/57933350 ## 感想 コンテスト本番中に解けなかった問題。 ハッシュを使わない方針もあると思ったが、面倒で貼ってしまった。