#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define allof(obj) (obj).begin(), (obj).end() #define range(i, l, r) for(int i=l;i>1)|y_bit)) #define bit_kth(i, k) ((i >> k)&1) #define bit_highest(i) (i?63-__builtin_clzll(i):-1) #define bit_lowest(i) (i?__builtin_ctzll(i):-1) #define sleepms(t) std::this_thread::sleep_for(std::chrono::milliseconds(t)) using ll = long long; using ld = long double; using ul = uint64_t; using pi = std::pair; using pl = std::pair; using namespace std; template std::ostream &operator<<(std::ostream &dest, const std::pair &p){ dest << p.first << ' ' << p.second; return dest; } template std::ostream &operator<<(std::ostream &dest, const std::vector> &v){ int sz = v.size(); if(sz==0) return dest; for(int i=0;i std::ostream &operator<<(std::ostream &dest, const std::vector &v){ int sz = v.size(); if(sz==0) return dest; for(int i=0;i std::ostream &operator<<(std::ostream &dest, const std::array &v){ if(sz==0) return dest; for(int i=0;i std::ostream &operator<<(std::ostream &dest, const std::set &v){ for(auto itr=v.begin();itr!=v.end();){ dest << *itr; itr++; if(itr!=v.end()) dest << ' '; } return dest; } template std::ostream &operator<<(std::ostream &dest, const std::map &v){ for(auto itr=v.begin();itr!=v.end();){ dest << '(' << itr->first << ", " << itr->second << ')'; itr++; if(itr!=v.end()) dest << '\n'; } return dest; } std::ostream &operator<<(std::ostream &dest, __int128_t value) { std::ostream::sentry s(dest); if (s) { __uint128_t tmp = value < 0 ? -value : value; char buffer[128]; char *d = std::end(buffer); do { --d; *d = "0123456789"[tmp % 10]; tmp /= 10; } while (tmp != 0); if (value < 0) { --d; *d = '-'; } int len = std::end(buffer) - d; if (dest.rdbuf()->sputn(d, len) != len) { dest.setstate(std::ios_base::badbit); } } return dest; } template vector make_vec(size_t sz, T val){return std::vector(sz, val);} template auto make_vec(size_t sz, Tail ...tail){ return std::vector(tail...))>(sz, make_vec(tail...)); } template vector read_vec(size_t sz){ std::vector v(sz); for(int i=0;i<(int)sz;i++) std::cin >> v[i]; return v; } template auto read_vec(size_t sz, Tail ...tail){ auto v = std::vector(tail...))>(sz); for(int i=0;i<(int)sz;i++) v[i] = read_vec(tail...); return v; } long long max(long long a, int b){return std::max(a, (long long)b);} long long max(int a, long long b){return std::max((long long)a, b);} long long min(long long a, int b){return std::min(a, (long long)b);} long long min(int a, long long b){return std::min((long long)a, b);} long long modulo(long long a, long long m){a %= m; return a < 0 ? a + m : a;} template struct safe_vector : std::vector{ using std::vector::vector; T& operator [](size_t i){return this->at(i);} }; template struct safe_array : std::array{ using std::array::array; T& operator [](size_t i){return this->at(i);} }; ll ceil_div(ll x, ll y){ assert(y > 0); return (x + (x > 0 ? y - 1 : 0)) / y; } ll floor_div(ll x, ll y){ assert(y > 0); return (x + (x > 0 ? 0 : -y + 1)) / y; } void io_init(){ std::cin.tie(nullptr); std::ios::sync_with_stdio(false); } std::vector stovector(const std::string &s){ int n = s.size(); std::vector res(n); for(int i = 0; i < n; i++) res[i] = s[i]; return res; } // cを0としてintに直す std::vector stovector_int(const std::string &s, char c = 'a'){ int n = s.size(); std::vector res(n); for(int i = 0; i < n; i++) res[i] = s[i] - c; return res; } #include std::vector split(const std::string &s, char delim){ std::vector elems; std::stringstream ss(s); std::string item; while(std::getline(ss, item, delim)){ if(!item.empty()) elems.push_back(item); } return elems; } template std::vector> runlength(const std::vector &v){ std::vector> ret; int n = v.size(); for(int i = 0; i < n; i++){ if(ret.empty() || ret.back().first != v[i]){ ret.push_back({v[i], 1}); }else{ ret.back().second++; } } return ret; } // 全ての要素が [0, NUM_VAL) template struct string_processor{ private: static constexpr int s = 64, sdiv = 6, smod = 63; using Z = uint64_t; int N; std::vector> B; std::vector> S; std::vector> V; public: string_processor(){} string_processor(const std::vector &v): N(v.size()){ int M = (N + s - 1) / s; V.resize(NUM_VAL, std::vector()); std::array pop; std::array pop_small; pop.fill(0); pop_small.fill(0); B.resize(M + 1, pop); S.resize(M, pop_small); for(int i = 0, t = 0, sz = 0; i < N; i++, t++){ int x = v[i]; assert(0 <= x && x < NUM_VAL); V[x].push_back(i); pop[x]++, pop_small[x] |= (Z(1) << t); if(t == s - 1 || i == N - 1){ for(int j = 0; j < NUM_VAL; j++){ if(j) pop[j] += pop[j - 1], pop_small[j] |= pop_small[j - 1]; B[sz + 1][j] = pop[j] + B[sz][j]; S[sz][j] = pop_small[j]; } pop.fill(0); pop_small.fill(0); t = -1; sz++; } } } // count c, i < r, O(1) int rank(int r, int c){ if(c == 0) return rank_lower(r, c); assert(0 <= r && r <= N); assert(0 <= c && c < NUM_VAL); int rq = r >> sdiv, rm = r & smod; int ret = B[rq][c] - B[rq][c - 1]; if(rm) ret += __builtin_popcountll((S[rq][c] ^ S[rq][c - 1]) << (s - rm)); return ret; } // count [0, c], i < r, O(1) int rank_lower(int r, int c){ assert(0 <= r && r <= N); assert(0 <= c && c < NUM_VAL); int rq = r >> sdiv, rm = r & smod; int ret = B[rq][c]; if(rm) ret += __builtin_popcountll(S[rq][c] << (s - rm)); return ret; } // k番目のc, ない場合は-1 O(1) int select(int k, int c){ assert(0 <= c && c < NUM_VAL); return (k < 0 || V[c].size() <= k) ? -1 : V[c][k]; } // k番目のc以下, ない場合は-1 O(logN) int select_lower(int k, int c){ assert(0 <= c && c < NUM_VAL); int l = 0, r = N + 1; while(r - l > 1){ int mid = (l + r) >> 1; if(rank_lower(mid, c) <= k) l = mid; else r = mid; } return r == N + 1 ? -1 : l; } // [i, n)で最も左のc int find_next(int i, int c){ return select(rank(i, c), c); } // [0, i]で最も右のc int find_prev(int i, int c){ return select(rank(i + 1, c) - 1, c); } }; unsigned long long random_once(){ static std::random_device seed_gen; static std::mt19937_64 engine(seed_gen()); static unsigned long long ret = engine(); return ret; } unsigned long long random_number(){ static std::random_device seed_gen; static std::mt19937_64 engine(seed_gen()); return engine(); } // [low, high] unsigned long long random_number(unsigned long long low, unsigned long long high){ static std::random_device seed_gen; static std::mt19937_64 engine(seed_gen()); assert(high >= low); unsigned long long diff = high - low + 1; return engine() % diff + low; } #include #include // ak + b のl <= k < rにおける和 template T arithmetic_sum(T a, T b, T l, T r){ return a * (r * (r - 1) - l * (l - 1)) / 2 + b * (r - l); } // a * k^2の l <= k < rにおける和 template T square_sum(T a, T l, T r){ return (r * (r - 1) * (2 * r - 1) - l * (l - 1) * (2 * l - 1)) / 6 * a; } // a^k * b のl <= k < rにおける和 // b * (a^r - a^l) / (a - 1) template T geometric_sum(T a, T b, T l, T r){ if(a == 1) return 0; return b * (a.pow(r) - a.pow(l)) / (a - 1); } // @param 0 <= b, a^bがオーバーフローしない long long llpow(long long a, long long b){ assert(0 <= b); long long ret = 1; while(b){ if(b & 1) ret *= a; a *= a; b >>= 1; } return ret; } // a^b, オーバーフローする場合numeric_limits // @param 0 <= a, b unsigned long long ullpow_of(unsigned long long a, unsigned long long b){ static constexpr unsigned long long inf = std::numeric_limits::max(); unsigned long long ret = 1; while(b){ if(b & 1){ if(ret >= inf / a) return inf; ret *= a; } a = (a >= inf / a ? inf : a * a); b >>= 1; } return ret; } long long gcd(long long _a, long long _b){ uint64_t a = abs(_a), b = abs(_b); if(a == 0) return b; if(b == 0) return a; int shift = __builtin_ctzll(a | b); a >>= __builtin_ctzll(a); do{ b >>= __builtin_ctzll(b); if(a > b) std::swap(a, b); b -= a; }while(b); return (a << shift); } // 64bitに収まらない可能性あり template long long lcm(T a, T b){ return __int128_t(a) * b / gcd(a, b); } // min(lcm(a, b), inf) template T lcm_limited(T a, T b, T inf){ if(a >= inf || b >= inf) return inf; b /= gcd(a, b); return (inf / a) < b ? inf : a * b; } std::tuple extgcd(long long a, long long b){ long long x, y; for(long long u = y = 1, v = x = 0; a;){ long long q = b / a; std::swap(x -= q * u, u); std::swap(y -= q * v, v); std::swap(b -= q * a, a); } return {x, y, b};//return {x, y, gcd(a, b)} s.t. ax + by = gcd(a, b) } constexpr long long __safe_mod(long long x, long long m){ x %= m; if (x < 0) x += m; return x; } // @param b `1 <= b` // @return pair(g, x) s.t. g = gcd(a, b), xa = g (mod b), 0 <= x < b/g constexpr std::pair inv_ext_gcd(long long a, long long b) { a = __safe_mod(a, b); if (a == 0) return {b, 0}; long long s = b, t = a; long long m0 = 0, m1 = 1; while (t){ long long u = s / t; s -= t * u; m0 -= m1 * u; auto tmp = s; s = t; t = tmp; tmp = m0; m0 = m1; m1 = tmp; } if (m0 < 0) m0 += b / s; return {s, m0}; } // {lcm, ans} std::pair crt(const std::vector& r, const std::vector& m){ assert(r.size() == m.size()); int n = int(r.size()); // Contracts: 0 <= r0 < m0 long long r0 = 0, m0 = 1; for(int i = 0; i < n; i++){ assert(1 <= m[i]); long long r1 = __safe_mod(r[i], m[i]), m1 = m[i]; if(m0 < m1){ std::swap(r0, r1); std::swap(m0, m1); } if(m0 % m1 == 0){ if(r0 % m1 != r1) return {0, 0}; continue; } long long g, im; std::tie(g, im) = inv_ext_gcd(m0, m1); long long u1 = (m1 / g); if ((r1 - r0) % g) return {0, 0}; long long x = (r1 - r0) / g % u1 * im % u1; r0 += x * m0; m0 *= u1; if (r0 < 0) r0 += m0; } return {r0, m0}; } // ai + bj = cの li <= i < ri かつ lj <= j < rjを満たす整数解 // 制約: a, b, c, li, ri, lj, riの絶対値が10^18以下(負でもいい) // a, b != 0 long long count_solution(long long a, long long b, long long c, long long li, long long ri, long long lj, long long rj){ if(li >= (ri--) || lj >= (rj--)) return 0; if(a < 0){ a *= -1, li *= -1, ri *= -1; std::swap(li, ri); } if(b < 0){ b *= -1, lj *= -1, rj *= -1; std::swap(lj, rj); } assert(a && b); auto [i, j, g] = extgcd(a, b); if(c % g != 0) return 0; a /= g, b /= g, c /= g; __int128_t i2 = (__int128_t)i * c; __int128_t j2 = (__int128_t)j * c; // 任意の整数kに対してa(i2 + bk) + b(j2 - ak) = cを満たす __int128_t lk1 = i2 >= li ? -(i2 - li) / b : (li - i2 + b - 1) / b; __int128_t rk1 = i2 >= ri ? -(i2 - ri + b - 1) / b : (ri - i2) / b; __int128_t lk2 = j2 >= rj ? (j2 - rj + a - 1) / a : -(rj - j2) / a; __int128_t rk2 = j2 >= lj ? (j2 - lj) / a : -(lj - j2 + a - 1) / a; lk1 = std::max(lk1, lk2); rk1 = std::min(rk1, rk2); if(lk1 > rk1) return 0; return rk1 - lk1 + 1; } // 2^k >= xとなる最小の2^k uint64_t ceil_2_pow(uint64_t x){ static uint64_t INF = std::numeric_limits::max(); uint64_t ret = uint64_t(1) << (63 - __builtin_clzll(x)); if(ret == x) return x; assert(ret <= (INF >> 1)); return ret << 1; } struct barrett_reduction{ unsigned int mod; unsigned long long m; barrett_reduction(unsigned int _mod) : mod(_mod){ m = ((__uint128_t)1 << 64) / mod; } unsigned int reduce(unsigned int a){ unsigned long long q = ((__uint128_t)a * m) >> 64; a -= q * mod; // 0 <= a < 2 * mod // return a; return a >= mod ? a - mod : a; } unsigned int mul(unsigned int a, unsigned int b){ return reduce((unsigned long long)a * b); } // {gcd(a, mod), x}, such that a * x ≡ gcd(a, mod) std::pair inv(unsigned int a){ if(a >= mod) a = reduce(a); if(a == 0) return {mod, 0}; unsigned int s = mod, t = a; long long m0 = 0, m1 = 1; while(t){ int u = s / t; s -= t * u; m0 -= m1 * u; std::swap(m0, m1); std::swap(s, t); } if(m0 < 0) m0 += mod / s; return {s, m0}; } }; // 64bit mod対応 // R = 2^64 // 偶数modだと壊れる struct montgomery_reduction_64bit{ private: // [0, 2 * MOD) inline uint64_t reduce_unsafe(__uint128_t x) const{ x = (x + ((uint64_t)x * (uint64_t)NEG_INV) * MOD) >> 64; return x; } void _set_mod(uint64_t mod){ assert((mod < (1ULL << 63)) && (mod & 1)); MOD = mod; NEG_INV = 0; __uint128_t s = 1, t = 0; for(int i = 0; i < 64; i++){ if (~t & 1) { t += MOD; NEG_INV += s; } t >>= 1; s <<= 1; } R2 = ((__uint128_t)1 << 64) % MOD; R2 = R2 * R2 % MOD; ONE = generate(1); } __uint128_t MOD, NEG_INV, R2; uint64_t ONE; public: montgomery_reduction_64bit(){} montgomery_reduction_64bit(uint64_t mod){_set_mod(mod);} void set_mod(uint64_t mod){ _set_mod(mod); } uint64_t mod()const{ return MOD; } inline uint64_t one()const{ return ONE; } inline uint64_t generate(uint64_t x)const{ return reduce((__uint128_t)x * R2); } inline uint64_t reduce(__uint128_t x)const{ x = (x + ((uint64_t)x * (uint64_t)NEG_INV) * MOD) >> 64; return x < MOD ? x : x - MOD; } inline uint64_t fix(uint64_t x)const{ return x < MOD ? x : x - MOD; } // [0, 2MOD) inline uint64_t mul(uint64_t mx, uint64_t my)const{ return reduce_unsafe((__uint128_t)mx * my); } inline uint64_t mul_safe(uint64_t mx, uint64_t my)const{ return reduce((__uint128_t)mx * my); } // [0, 2MOD) inline uint64_t add(uint64_t mx, uint64_t my)const{ return (mx >= MOD ? mx - MOD : mx) + (my >= MOD ? my - MOD : my); } inline uint64_t add_safe(uint64_t mx, uint64_t my)const{ uint64_t res = (mx >= MOD ? mx - MOD : mx) + (my >= MOD ? my - MOD : my); return res >= MOD ? res - MOD : res; } // [0, 2MOD) inline uint64_t sub(uint64_t mx, uint64_t my)const{ if(my >= MOD) my -= MOD; return mx >= my ? mx - my : mx + MOD - my; } inline uint64_t sub_safe(uint64_t mx, uint64_t my)const{ if(my >= MOD) my -= MOD; uint64_t res = mx >= my ? mx - my : mx + MOD - my; return res >= MOD ? res - MOD : res; } inline uint64_t pow(uint64_t ma, uint64_t b)const{ uint64_t ret = one(); while(b){ if(b & 1) ret = mul(ret, ma); ma = mul(ma, ma); b >>= 1; } return ret; } inline uint64_t pow_safe(uint64_t ma, uint64_t b)const{ return fix(pow(ma, b)); } }; unsigned long long mod_pow_mr(unsigned long long a, unsigned long long b, unsigned long long m){ montgomery_reduction_64bit mr(m); return mr.reduce(mr.pow(mr.generate(a), b)); } namespace prime_sieve{ std::vector primes, min_factor;// 素数, 各数を割り切る最小の素数 // O(MAX_N loglog MAX_N) // [1, MAX_N]を扱えるように初期化 void init(int MAX_N){ min_factor.resize(MAX_N + 1, -1); for(int i = 2; i <= MAX_N; i++){ if(min_factor[i] == -1){ primes.push_back(i); min_factor[i] = i; } for(int p : primes){ if((long long)p * i > MAX_N || p > min_factor[i]) break; min_factor[p * i] = p; } } } bool is_prime(int n){ assert(n < min_factor.size()); return n == min_factor[n]; } // {{素因数, 数}}, O(log n) std::vector> factorize(int n){ assert(n < min_factor.size()); std::vector> ret; while(n > 1){ int cnt = 0, f = min_factor[n]; while(n % f == 0){ n /= f; cnt++; } ret.push_back({f, cnt}); } return ret; } // 約数列挙, O(√n) std::vector divisor(int n){ auto p = factorize(n); std::vector> x; for(int i = 0; i < p.size(); i++){ x.push_back(std::vector{1}); for(int j = 0; j < p[i].second; j++) x[i].push_back(x[i][j] * p[i].first); } int l = 0, r = 1; std::vector ret{1}; for(int i = 0; i < x.size(); i++){ for(auto e : x[i]){ for(int j = l; j < r; j++){ ret.push_back(ret[j] * e); } } l = r; r = ret.size(); } return std::vector(ret.begin() + l, ret.end()); } // O(logN) unsigned long long totient_function(unsigned long long n){ unsigned long long res = n; int prev = -1; while(n > 1){ if(min_factor[n] > prev){ res -= res / min_factor[n]; prev = min_factor[n]; } n /= min_factor[n]; } return res; } int mobius_function(int x){ int pcnt = 0; while(x > 1){ int y = x / min_factor[x]; if(min_factor[x] == min_factor[y]) return 0; x = y; pcnt++; } return pcnt % 2 == 0 ? 1 : -1; } }; bool _miller_rabin_mr(unsigned long long n, const montgomery_reduction_64bit &mr){ static std::vector small_p{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47}; static std::vector A{2, 325, 9375, 28178, 450775, 9780504, 1795265022}; static std::vector B{2, 7, 61}; if(n <= 1) return false; if(n <= 50){ for(int l = n < 20 ? 0 : 8, r = n < 20 ? 8 : 15; l < r; l++) if(small_p[l] == n) return true; return false; } if(!(n & 1)) return false; unsigned long long d = n - 1; unsigned long long one = mr.one(), mone = mr.generate(n - 1); d >>= __builtin_ctzll(d); for(unsigned long long a : (n >> 32) ? A : B){ if(a % n == 0) continue; unsigned long long d2s = d; // d * 2^s, 0 <= s <= (n - 1)が2で割れる回数 unsigned long long y = mr.pow_safe(mr.generate(a), d); while(d2s != n - 1 && y != one && y != mone){ y = mr.mul_safe(y, y); d2s <<= 1; } if(y != mone && !(d2s & 1)) return false; } return true; } bool miller_rabin_mr(unsigned long long n){ if(n % 2 == 0) return n == 2 ? true : false; montgomery_reduction_64bit mr(n); return _miller_rabin_mr(n, mr); } // https://en.wikipedia.org/wiki/Binary_GCD_algorithm unsigned long long binary_gcd(unsigned long long a, unsigned long long b){ if(!a || !b) return !a ? b : a; int shift = __builtin_ctzll(a | b); // [1] gcd(2a', 2b') = 2 * gcd(a', b') a >>= __builtin_ctzll(a); do{ // if b is odd // gcd(2a', b) = gcd(a', b), if a = 2a'(a is even) // gcd(a, b) = gcd(|a - b|, min(a, b)), if a is odd b >>= __builtin_ctzll(b); // make b odd if(a > b) std::swap(a, b); b -= a; }while(b); // gcd(a, 0) = a return a << shift; // [1] } unsigned long long generate_random_prime(unsigned long long min_n = 2, unsigned long long max_n = ~0ULL){ std::random_device seed_gen; std::mt19937_64 engine(seed_gen()); __uint128_t len = max_n - min_n + 1; // https://en.wikipedia.org/wiki/Prime_number_theorem while(true){ unsigned long long a = engine() % len + min_n; if(miller_rabin_mr(a)){ return a; } } } namespace rho_factorization{ unsigned long long rho(unsigned long long n){ static std::vector small_p{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47}; for(int sp : small_p) if(n % sp == 0) return sp; // n < 50 montgomery_reduction_64bit mr(n); if(_miller_rabin_mr(n, mr)) return n; auto try_factorize = [n, mr](unsigned long long c){ c = mr.generate(c); auto f = [mr, c](unsigned long long mx){ return mr.add(mr.mul(mx, mx), c); }; unsigned long long m = 1LL << ((64 - __builtin_clzll(n)) / 8); unsigned long long y = n, r = 1, q = 1; unsigned long long x, g, k, ys; do{ x = y; y = mr.generate(y); for(int i = 0; i < r; i++) y = f(y); y = mr.reduce(y); k = 0; while(k < r && g == 1){ q = mr.generate(q); y = mr.generate(y); ys = y; for(int i = 0; i < std::min(m, r - k); i++){ y = f(y); unsigned long long z = mr.reduce(y); q = mr.mul(q, mr.generate(x > z ? x - z : z - x)); } y = mr.reduce(y); g = binary_gcd(mr.reduce(q), n); k += m; } r <<= 1; }while(g == 1); if(g == n){ do{ ys = f(ys); unsigned long long z = mr.reduce(ys); g = binary_gcd(x > z ? x - z : z - x, n); }while(g == 1); } return g; // g == n when failure }; unsigned long long c = 1, res = n; do{ res = try_factorize(c); // c = generate_random_prime(2, n - 1); c = (c + 1) % n; }while(res == n); return res; } std::vector factorize(unsigned long long n){ if(n <= 1) return {}; unsigned long long x = rho(n); if(x == n) return {x}; auto l = factorize(x); auto r = factorize(n / x); l.insert(l.end(), r.begin(), r.end()); return l; } // {素数, 個数}の形で返す std::vector> factorize2(unsigned long long n){ auto p = factorize(n); sort(p.begin(), p.end()); std::vector> ret; for(int i : p){ if(ret.empty() || ret.back().first != i) ret.push_back({i, 1}); else ret.back().second++; } return ret; } // 素因数の集合(重複なし, ソート済)を返す std::vector prime_factor(unsigned long long n){ auto p = factorize(n); std::sort(p.begin(), p.end()); p.erase(std::unique(p.begin(), p.end()), p.end()); return p; } // 10^18以下の高度合成数 897612484786617600の約数が103680個なので全列挙して良さそう std::vector divisor(unsigned long long n){ auto p = factorize(n); std::sort(p.begin(), p.end()); std::vector> x; for(int i = 0; i < p.size(); i++){ if(!i || p[i] != p[i - 1]) x.push_back({p[i], 1}); else x.back().second++; } int sz = 1; for(auto [p_cur, cnt] : x) sz *= cnt + 1; std::vector res(sz); res[0] = 1; int r_prev = 1, r = 1; for(auto [p_cur, cnt] : x){ unsigned long long ppow = 1; for(int c = 0; c < cnt; c++){ ppow *= p_cur; for(int i = 0; i < r_prev; i++){ res[r++] = res[i] * ppow; } } r_prev = r; } return res; } int mobius_function(long long x){ auto P = rho_factorization::factorize(x); for(long long p : P) if((x / p) % p == 0) return 0; return P.size() % 2 == 0 ? 1 : -1; } unsigned long long totient_function(unsigned long long n){ unsigned long long res = n; auto prims = rho_factorization::prime_factor(n); for(auto p : prims) res -= res / p; return res; } }; // p: 素数 unsigned long long find_primitive_root(unsigned long long p){ static std::random_device seed_gen; static std::mt19937_64 engine(seed_gen()); //assert(miller_rabin_mr(p)); auto primes = rho_factorization::prime_factor(p - 1); while(true){ bool f = true; unsigned long long a = engine() % (p - 1) + 1; for(unsigned long long pk : primes){ // a ^ (p - 1) / pk ≡ 1 (mod p) -> no if(mod_pow_mr(a, (p - 1) / pk, p) == 1){ f = false; break; } } if(f) return a; } } struct bigint_prime_factor{ int sq, max_x; std::vector low; std::unordered_map high; bigint_prime_factor(int max_x): sq(sqrt(max_x)), max_x(max_x), low(sq + 1, 0){ // 篩が初期化済か assert(prime_sieve::min_factor.size() > max_x); } // O(log(x)) // x^kを掛ける void mul(int x, int k = 1){ assert(0 < x && x <= max_x); while(x > 1){ int p = prime_sieve::min_factor[x]; if(p <= sq) low[p] += k; else{ auto [itr, f] = high.emplace(x, k); if(!f) itr->second += k; } x /= p; } } // O(log(x)) // x^kで割る(割り切れない場合エラー) void div(int x, int k = 1){ assert(0 < x && x <= max_x); while(x > 1){ int p = prime_sieve::min_factor[x]; if(p <= sq){ assert(low[p] >= k); low[p] -= k; }else{ auto itr = high.find(p); assert(itr != high.end() && itr->second >= k); itr->second -= k; if(itr->second == 0) high.erase(itr); } x /= p; } } // 素数pで何回割れるか, O(1) // pが素数でない場合0 int k_divisible_prime(int p){ if(p > max_x || !prime_sieve::is_prime(p)) return 0; if(p > sq){ auto itr = high.find(p); return itr == high.end() ? 0 : itr->second; } return low[p]; } // xで何回割れるか, O(log(x)) // x = 1のときinf回割れる // @param 0 < x <= 篩の最大値 int k_divisible(int x){ assert(x > 0); static constexpr int inf = std::numeric_limits::max(); int ans = inf; for(auto [p, num] : prime_sieve::factorize(x)){ if(p > sq){ auto itr = high.find(p); if(itr == high.end()) return 0; ans = std::min(ans, itr->second / num); }else{ ans = std::min(ans, low[p] / num); } } return ans; } // rで何回割り切れるか, O(sqrt(r.max_x)以下の素数 + rの素因数の種類) int k_divisible(const bigint_prime_factor &r){ static constexpr int inf = std::numeric_limits::max(); int ans = inf; for(int i = 0; prime_sieve::primes[i] <= r.sq; i++){ int p = prime_sieve::primes[i]; if(!r.low[p]) continue; if(p <= sq){ if(low[p] < r.low[p]) return 0; ans = std::min(ans, low[p] / r.low[p]); }else{ auto itr = high.find(p); if(itr->second < r.low[p]) return 0; ans = std::min(ans, itr->second / r.low[p]); } } for(auto [p, num] : r.high){ assert(num); if(p <= sq){ if(low[p] < num) return 0; ans = std::min(ans, low[p] / num); }else{ auto itr = high.find(p); if(itr->second < num) return 0; ans = std::min(ans, itr->second / num); } } return ans; } }; // res[i] := v[i]の位数 template std::vector multiplicative_order_many(const std::vector &v){ int n = v.size(); std::vector res(n, 1); for(auto [p, q] : rho_factorization::factorize2(mint::mod() - 1)){ long long x = mint(p).pow(q).val(), y = (mint::mod() - 1) / x; for(int i = 0; i < n; i++){ long long z = x; for(int j = 0; j < q; j++){ z /= p; if(v[i].pow(y * z).val() != 1){ res[i] *= z * p; break; } } } } return res; } // 要素はモンゴメリ表現に変換せずに演算する struct montgomery_rolling_hash{ using ull = unsigned long long; using ulll = __uint128_t; static ull r, rinv, mod; static std::vector rpow, rinvpow, run_inv; static montgomery_reduction_64bit mr; // run関数をO(1)で使いたい場合はuse_run = true static void init(int max_n, bool use_run = false){ assert(0 < max_n || rpow.empty()); // 2回呼び出されると壊れる mod = generate_random_prime(1ULL << 58, 1ULL << 63); // 小さすぎず, 足してもullでオーバーフローしない mr.set_mod(mod); r = random_number(1, mod - 1); ull g; std::tie(g, rinv) = inv_ext_gcd(r, mod); assert(g == 1); // r != 0 && is_prime(mod) -> gcd(r, mod) == 1 r = mr.generate(r); rinv = mr.generate(rinv); rpow.resize(max_n + 1); rinvpow.resize(max_n + 1); run_inv.resize(max_n + 1); rpow[0] = rinvpow[0] = run_inv[0] = mr.generate(1); ull one = mr.generate(1); for(int i = 1; i <= max_n; i++){ rpow[i] = mr.mul_safe(rpow[i - 1], r); rinvpow[i] = mr.mul_safe(rinvpow[i - 1], rinv); if(use_run) run_inv[i] = mr.pow_safe(mr.sub_safe(rpow[i], one), mod - 2); // 1 / (rpow[i] - 1)のモンゴメリ表現, i != 0 } } template static ull __mod(T x){ x %= mod; return x < 0 ? mod + x : x; } static ull hash(const std::string &s){ assert(s.size() <= rpow.size()); ull res = 0; for(int i = 0; i < s.size(); i++) res = mr.add(res, mr.mul(rpow[i], s[i])); return mr.fix(res); } // 要素aが負の場合やaがmod以上の場合, aとa + modが同一視される template static ull hash(const std::vector &s){ assert(s.size() <= rpow.size()); ull res = 0; for(int i = 0; i < s.size(); i++) res = mr.add(res, mr.mul(rpow[i], __mod(s[i]))); return mr.fix(res); } // table[i] = [0, i)のハッシュテーブル template static std::vector hash_table(const std::vector &s){ assert(s.size() <= rpow.size()); std::vector res(s.size() + 1); res[0] = 0; for(int i = 0; i < s.size(); i++){ res[i + 1] = mr.add_safe(res[i], mr.mul(rpow[i], __mod(s[i]))); } return res; } // xがk文字目にあった時のハッシュ template static ull get(int k, T x){ assert(k < rpow.size()); return mr.mul_safe(rpow[k], __mod(x)); } static ull mul(ull a, ull b){ return mr.mul_safe(a, b); } static ull add(ull a, ull b){ return mr.add_safe(a, b); } static ull sub(ull a, ull b){ return mr.sub_safe(a, b); } // a^b static ull pow(ull a, ull b){ return mr.pow_safe(a, b); } // 長さalenのハッシュがaの文字の末尾にハッシュがbの文字を結合する // O(1)またはO(log alen) static ull concat(ull a, ull alen, ull b){ if(alen < rpow.size()) return add(a, mul(rpow[alen], b)); return add(a, mul(pow(r, alen), b)); } // 長さalenのハッシュがaの文字をk回繰り返す // a + a * rpow[alen] + a * rpow[2 * alen] ... // = a * (rpow[k * alen] - 1) / (rpow[alen] - 1) static ull run(ull a, ull alen, ull k){ if(alen == 0) return 0; if(k <= 1) return k ? a : 0; __uint128_t K = k * alen; if(K < (int)rpow.size()) return mul(a, mul(sub(rpow[K], run_inv[0]), run_inv[alen])); // rpow[alen] unsigned long long r_alen = (alen < rpow.size() ? rpow[alen] : mr.pow_safe(r, alen)); // rpow[k * alen] unsigned long long r_K = mr.pow_safe(r_alen, k); // 1 / (rpow[alen] - 1) r_alen = mr.pow_safe(sub(r_alen, run_inv[0]), mod - 2); return mul(a, mul(sub(r_K, run_inv[0]), r_alen)); } }; unsigned long long montgomery_rolling_hash::r = 0; unsigned long long montgomery_rolling_hash::rinv = 0; unsigned long long montgomery_rolling_hash::mod = 0; std::vector montgomery_rolling_hash::rpow; std::vector montgomery_rolling_hash::rinvpow; std::vector montgomery_rolling_hash::run_inv; montgomery_reduction_64bit montgomery_rolling_hash::mr; // モンゴメリ乗算の方が早い /* struct rolling_hash61{ using ull = unsigned long long; static constexpr ull mod = (1UL << 61) - 1; static constexpr ull mod4 = (mod << 2); static constexpr ull mask30 = (1UL << 30) - 1; static constexpr ull mask31 = (1UL << 31) - 1; static constexpr ull mask61 = mod; static ull r, rinv; static std::vector rpow, rinvpow, run_inv; template static ull __mod(T x){ x %= mod; return x < 0 ? mod + x : x; } static ull calc_mod(ull a){ ull au = a >> 61, ad = a & mask61; ull b = au + ad; return b >= mod ? b - mod : b; } static ull add(ull a, ull b){ ull c = a + b; return c >= mod ? c - mod : c; } static ull sub(ull a, ull b){ return a < b ? a + mod - b : a - b; } static ull mul(ull a, ull b){ ull au = a >> 31, ad = a & mask31; ull bu = b >> 31, bd = b & mask31; ull c = ad * bu + au * bd; ull cu = c >> 30, cd = c & mask30; return calc_mod(au * bu * 2 + cu + (cd << 31) + ad * bd); } // a^b static ull pow(ull a, ull b){ ull c = 1; while(b){ if(b & 1) c = mul(c, a); a = mul(a, a); b >>= 1; } return c; } static void init(int max_n, bool use_run = false){ assert(0 < max_n || rpow.empty()); // 2回呼び出されると壊れる r = random_number(2, mod - 1); ull g; std::tie(g, rinv) = inv_ext_gcd(r, mod); rpow.resize(max_n + 1); rinvpow.resize(max_n + 1); run_inv.resize(max_n + 1); rpow[0] = rinvpow[0] = run_inv[0] = 1; for(int i = 1; i <= max_n; i++){ rpow[i] = mul(rpow[i - 1], r); rinvpow[i] = mul(rinvpow[i - 1], rinv); if(use_run) run_inv[i] = pow(sub(rpow[i], 1), mod - 2); // 1 / (rpow[i] - 1) } } static ull hash(const std::string &s){ assert(s.size() <= rpow.size()); ull res = 0; for(int i = 0; i < s.size(); i++) res = add(res, mul(rpow[i], s[i])); return res; } // 要素aが負の場合やaがmod以上の場合, aとa + modが同一視される template static ull hash(const std::vector &s){ assert(s.size() <= rpow.size()); ull res = 0; for(int i = 0; i < s.size(); i++) res = add(res, mul(rpow[i], __mod(s[i]))); return res; } // table[i] = [0, i)のハッシュテーブル template static std::vector hash_table(const std::vector &s){ assert(s.size() <= rpow.size()); std::vector res(s.size() + 1); res[0] = 0; for(int i = 0; i < s.size(); i++) res[i + 1] = add(res[i], mul(rpow[i], __mod(s[i]))); return res; } // xがk文字目にあった時のハッシュ template static ull get(int k, T x){ assert(k < rpow.size()); return mul(rpow[k], __mod(x)); } // 長さalenのハッシュがaの文字の末尾にハッシュがbの文字を結合する // O(1)またはO(log alen) static ull concat(ull a, ull alen, ull b){ if(alen < rpow.size()) return add(a, mul(rpow[alen], b)); return add(a, mul(pow(r, alen), b)); } // 長さalenのハッシュがaの文字をk回繰り返す // a + a * rpow[alen] + a * rpow[2 * alen] ... // = a * (rpow[k * alen] - 1) / (rpow[alen] - 1) static ull run(ull a, ull alen, ull k){ if(alen == 0) return 0; if(k <= 1) return k ? a : 0; __uint128_t K = k * alen; if(K < (int)rpow.size()) return mul(a, mul(sub(rpow[K], run_inv[0]), run_inv[alen])); // rpow[alen] unsigned long long r_alen = (alen < rpow.size() ? rpow[alen] : pow(r, alen)); // rpow[k * alen] unsigned long long r_K = pow(r_alen, k); // 1 / (rpow[alen] - 1) r_alen = pow(sub(r_alen, run_inv[0]), mod - 2); return mul(a, mul(sub(r_K, run_inv[0]), r_alen)); } }; unsigned long long rolling_hash61::r = 0; unsigned long long rolling_hash61::rinv = 0; std::vector rolling_hash61::rpow; std::vector rolling_hash61::rinvpow; std::vector rolling_hash61::run_inv; */ struct rolling_hash_string{ using ull = unsigned long long; using rh = montgomery_rolling_hash; private: int n; std::vector sum; public: template rolling_hash_string(const std::vector &_v): n(_v.size()), sum(rh::hash_table(_v)){} int size() const{ return n; } ull get(int k) const{ assert(k < n); return rh::mul(rh::sub(sum[k + 1], sum[k]), rh::rinvpow[k]); } template void push_back(T x){ ull h = rh::add(sum.back(), rh::mul(rh::__mod(x), rh::rpow[n])); sum.push_back(h); n++; } void pop_back(){ assert(n); sum.pop_back(); n--; } // 全体のハッシュ ull hash_all() const{ return sum.back(); } // [l, r)のハッシュ // l == rなら0 ull hash_range(int l, int r) const{ assert(0 <= l && l <= r && r <= n); if(!l) return sum[r]; return rh::mul(rh::sub(sum[r], sum[l]), rh::rinvpow[l]); } // 結合後のサイズがmontgomeryテーブルのサイズを超えない void concat(const rolling_hash_string &b){ int m = b.size(); assert(n + m < rh::rpow.size()); unsigned long long x = rh::rpow[n], y = sum.back(); for(int i = 1; i <= m; i++) sum.push_back(rh::add(y, rh::mul(b.sum[i], x))); n += m; } // aの[l1...]とbの[l2...]のlcp static int lcp(const rolling_hash_string &a, const rolling_hash_string &b, int l1, int l2){ int L = 0, R = std::min(a.size() - l1, b.size() - l2) + 1; while(R - L > 1){ int mid = (L + R) >> 1; if(a.hash_range(l1, l1 + mid) == b.hash_range(l2, l2 + mid)) L = mid; else R = mid; } return L; } // これの[l1...]とbの[l2...]のlcp int lcp(const rolling_hash_string &b, int l1, int l2) const{ return lcp(*this, b, l1, l2); } }; struct dynamic_rolling_hash_string{ using ull = unsigned long long; using rh = montgomery_rolling_hash; private: int n, h; std::vector sum, point; void __init(std::vector &v){ sum.resize(1, 0); sum.insert(sum.begin() + 1, v.begin(), v.end()); for(int i = 1; i <= n; i++){ int nxt = i + (i & (-i)); if(nxt <= n) sum[nxt] = rh::add(sum[nxt], sum[i]); } if(n) h = 31 - __builtin_clz(n); } void __update(int k, ull x){ for(int i = k + 1; i <= n; i += (i & (-i))){ sum[i] = rh::add(sum[i], x); } } ull __query(int r) const{ ull res = 0; for(int k = r; k > 0; k -= (k & (-k))){ res = rh::mr.add(res, sum[k]); } return rh::mr.fix(res); } ull __query(int l, int r) const{ ull a = __query(r), b = __query(l); return rh::sub(a, b); } ull __query_all() const{ return __query(n); } public: template dynamic_rolling_hash_string(const std::vector &_v): n(_v.size()){ std::vector table(n); point.resize(n); for(int i = 0; i < n; i++){ table[i] = rh::get(i, _v[i]); point[i] = rh::__mod(_v[i]); } __init(table); } int size() const{ return n; } template void set(int k, T x){ ull _x = rh::__mod(x), _y = get(k); point[k] = _x; __update(k, rh::mul(rh::sub(_x, _y), rh::rpow[k])); } ull get(int k) const{ assert(0 <= k && k < n); return point[k]; } // 全体のハッシュ ull hash_all() const{ return __query_all(); } // [0, r)のハッシュ ull hash_range(int r) const{ return __query(r); } // [l, r)のハッシュ // l == rなら0 ull hash_range(int l, int r) const{ assert(0 <= l && l <= r && r <= n); if(l == 0) return __query(r); return rh::mul(__query(l, r), rh::rinvpow[l]); } static int lcp(const dynamic_rolling_hash_string &a, const dynamic_rolling_hash_string &b, int l1, int l2){ int v = 1 << a.h, H = a.h; ull s = rh::sub(0, a.__query(l1)); ull hash_b = b.__query(l2); while(H--){ int len = v - l1; if(a.n < v || l2 + len > b.size()){ v -= 1 << H; continue; } ull hash_tmp = rh::add(s, a.sum[v]); if(v <= l1){ s = hash_tmp; v += 1 << H; continue; } bool f = rh::mul(rh::sub(b.__query(l2 + len), hash_b), rh::rinvpow[l2]) != rh::mul(hash_tmp, rh::rinvpow[l1]); if(f){ v -= 1 << H; }else{ s = hash_tmp; v += 1 << H; } } if(v == a.n + 1) return a.n - l1; int len = v - l1; bool f = l2 + len > b.size() || b.hash_range(l2, l2 + len) != rh::mul(rh::add(s, a.sum[v]), rh::rinvpow[l1]); return f ? v - 1 - l1 : v - l1; } // len(a) == len(b)かつ0からのlcp O(loglen(a)) static int lcp_same_size(const dynamic_rolling_hash_string &a, const dynamic_rolling_hash_string &b){ assert(a.size() == b.size()); int v = 1 << a.h, H = a.h; while(H--){ if(a.n < v) v -= 1 << H; else if(a.sum[v] != b.sum[v]) v -= 1 << H; else v += 1 << H; } if(v == a.n + 1) return a.n; return a.sum[v] != b.sum[v] ? v - 1 : v; } static int lcp(const dynamic_rolling_hash_string &a, const rolling_hash_string &b, int l1, int l2){ int v = 1 << a.h, H = a.h; ull s = rh::sub(0, a.__query(l1)); while(H--){ int len = v - l1; if(a.n < v || l2 + len > b.size()){ v -= 1 << H; continue; } ull hash_tmp = rh::add(s, a.sum[v]); if(v <= l1){ s = hash_tmp; v += 1 << H; continue; } bool f = b.hash_range(l2, l2 + len) != rh::mul(hash_tmp, rh::rinvpow[l1]); if(f){ v -= 1 << H; }else{ s = hash_tmp; v += 1 << H; } } if(v == a.n + 1) return a.n - l1; int len = v - l1; bool f = l2 + len > b.size() || b.hash_range(l2, l2 + len) != rh::mul(rh::add(s, a.sum[v]), rh::rinvpow[l1]); return f ? v - 1 - l1 : v - l1; } static int lcp(const rolling_hash_string &a, const dynamic_rolling_hash_string &b, int l1, int l2){ return lcp(b, a, l2, l1); } }; struct dynamic_rolling_hash_string_persistent{ using ull = unsigned long long; using rh = montgomery_rolling_hash; private: struct node{ node *l, *r; int sz; ull val; node(ull x): l(nullptr), r(nullptr), sz(1), val(x){} node(node *l, node *r): l(l), r(r), sz(l->sz + r->sz), val(rh::add(l->val, rh::mul(r->val, rh::rpow[l->sz]))){} }; template static node *__build(const std::vector &v, int l, int r){ if(l + 1 == r) return new node(v[l]); int mid = (l + r) / 2; return new node(__build(v, l, mid), __build(v, mid, r)); } static node *__set(node *v, int k, ull x, int l, int r){ if(r - l == 1) return new node(x); int mid = (l + r) / 2; if(k < mid){ return new node(__set(v->l, k, x, l, mid), v->r); }else{ return new node(v->l, __set(v->r, k, x, mid, r)); } } static ull __get(node *v, int k, int l, int r){ if(r - l == 1) return v->val; int mid = (l + r) / 2; if(k < mid) return __get(v->l, k, l, mid); else return __get(v->r, k, mid, r); } static ull __hash_range(node *v, int b){ int l = 0, r = v->sz; b = std::min(b, r); int lsz = 0; ull res = 0; while(v){ if(b <= l) return res; if(b >= r) return rh::add(res, rh::mul(v->val, rh::rpow[lsz])); int mid = (l + r) / 2; if(b <= mid){ r = mid; v = v->l; }else{ res = rh::add(res, rh::mul(v->l->val, rh::rpow[lsz])); lsz += mid - l; l = mid; v = v->r; } } return res; } static ull __hash_range(node *v, int a, int b, int l, int r){ if(!v || b <= l || r <= a) return 0; if(a <= l && r <= b) return v->val; int mid = (l + r) / 2; return rh::add(__hash_range(v->l, a, b, l, mid), rh::mul(__hash_range(v->r, a, b, mid, r), rh::rpow[mid - l])); } public: dynamic_rolling_hash_string_persistent(){} template static node *build(const std::vector &v){ int n = v.size(); return __build(v, 0, n); } static int size(node *v){ return v ? v->sz : 0; } static node *set(node *v, int k, ull x){ assert(k < size(v)); return __set(v, k, x, 0, v->sz); } static ull get(node *v, int k){ assert(k < size(v)); return __get(v, k, 0, v->sz); } static ull hash_range(node *v, int r){ assert(0 <= r && r <= size(v)); if(r == 0) return 0; return __hash_range(v, r); } static ull hash_range(node *v, int l, int r){ if(l >= r) return 0; assert(0 <= l && r <= size(v)); return __hash_range(v, l, r, 0, v->sz); } static int __lcp(node *v, const rolling_hash_string &b, int l1, int l2){ if(!v || l2 >= b.size()) return 0; if(l1 == 0 && l2 + v->sz <= b.size() && v->val == b.hash_range(l2, l2 + v->sz)) return v->sz; int szl = v->l ? v->l->sz : 0; if(szl <= l1) return __lcp(v->r, b, l1 - szl, l2); int left_cross = szl - l1, L = __lcp(v->l, b, l1, l2); if(L != left_cross) return L; l2 += left_cross; return L + __lcp(v->r, b, 0, l2); } static int __lcp(node *v, const dynamic_rolling_hash_string &b, int l1, int l2, int &oksz, ull &ok){ if(!v || l2 >= b.size()) return 0; if(l1 == 0 && l2 + v->sz <= b.size()){ ull rh = rh::mul(rh::sub(b.hash_range(l2 + v->sz), ok), rh::rinvpow[l2]); if(v->val == rh){ ok = rh::add(ok, rh::mul(v->val, rh::rpow[oksz])); oksz += v->sz; return v->sz; } } int szl = v->l ? v->l->sz : 0; if(szl <= l1) return __lcp(v->r, b, l1 - szl, l2, oksz, ok); int left_cross = szl - l1, L = __lcp(v->l, b, l1, l2, oksz, ok); if(L != left_cross) return L; l2 += left_cross; return L + __lcp(v->r, b, 0, l2, oksz, ok); } static int __lcp(node *v, node *u, int l1, int l2, int &oksz, ull &ok){ if(!v || l2 >= size(u)) return 0; if(l1 == 0 && l2 + v->sz <= size(u)){ ull rh = rh::mul(rh::sub(hash_range(u, l2 + v->sz), ok), rh::rinvpow[l2]); if(v->val == rh){ ok = rh::add(ok, rh::mul(v->val, rh::rpow[oksz])); oksz += v->sz; return v->sz; } } int szl = v->l ? v->l->sz : 0; if(szl <= l1) return __lcp(v->r, u, l1 - szl, l2, oksz, ok); int left_cross = szl - l1, L = __lcp(v->l, u, l1, l2, oksz, ok); if(L != left_cross) return L; l2 += left_cross; return L + __lcp(v->r, u, 0, l2, oksz, ok); } static int lcp(node *v, const rolling_hash_string &b, int l1, int l2){ if(!v) return 0; return __lcp(v, b, l1, l2); } static int lcp(const rolling_hash_string &b, node *v, int l1, int l2){ if(!v) return 0; return __lcp(v, b, l2, l1); } static int lcp(node *v, const dynamic_rolling_hash_string &b, int l1, int l2){ int oksz = l2; ull ok = b.hash_range(l2); return __lcp(v, b, l1, l2, oksz, ok); } static int lcp(const dynamic_rolling_hash_string &a, node *v, int l1, int l2){ return lcp(v, a, l2, l1); } static int lcp(node *v, node *u, int l1, int l2){ int oksz = l2; ull ok = hash_range(u, 0, l2); return __lcp(v, u, l1, l2, oksz, ok); } }; int main(){ io_init(); int n; std::cin >> n; using H = montgomery_rolling_hash; H::init(100000); using ull = unsigned long long; map mp; vector S(n); range(i, 0, n){ vector cnt(26, 0); string s; std::cin >> s; S[i] = s; range(j, 0, s.size()) cnt[s[j] - 'a']++; range(j, 0, 26){ cnt[j]++; auto h = H::hash(cnt); auto itr = mp.find(h); if(itr == mp.end()) mp.emplace(h, 1); else itr->second++; cnt[j]--; } } range(i, 0, n){ vector cnt(26, 0); string s = S[i]; range(j, 0, s.size()) cnt[s[j] - 'a']++; range(j, 0, 26){ cnt[j]++; auto h = H::hash(cnt); auto itr = mp.find(h); if(itr != mp.end() && itr->second == 1){ string ans = ""; range(k, 0, 26) ans += string(cnt[k], 'a' + k); std::cout << ans << '\n'; return 0; } cnt[j]--; } } std::cout << -1 << '\n'; }