QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#74743 | #5442. Referee Without Red | Nyaan | RE | 8ms | 16028kb | C++17 | 24.3kb | 2023-02-03 17:12:27 | 2023-02-03 17:12:29 |
Judging History
answer
/**
* date : 2023-02-03 18:12:13
*/
#define NDEBUG
using namespace std;
// intrinstic
#include <immintrin.h>
#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <cctype>
#include <cfenv>
#include <cfloat>
#include <chrono>
#include <cinttypes>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdarg>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <deque>
#include <fstream>
#include <functional>
#include <initializer_list>
#include <iomanip>
#include <ios>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <streambuf>
#include <string>
#include <tuple>
#include <type_traits>
#include <typeinfo>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
// utility
namespace Nyaan {
using ll = long long;
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
template <typename T>
using V = vector<T>;
template <typename T>
using VV = vector<vector<T>>;
using vi = vector<int>;
using vl = vector<long long>;
using vd = V<double>;
using vs = V<string>;
using vvi = vector<vector<int>>;
using vvl = vector<vector<long long>>;
template <typename T, typename U>
struct P : pair<T, U> {
template <typename... Args>
P(Args... args) : pair<T, U>(args...) {}
using pair<T, U>::first;
using pair<T, U>::second;
P &operator+=(const P &r) {
first += r.first;
second += r.second;
return *this;
}
P &operator-=(const P &r) {
first -= r.first;
second -= r.second;
return *this;
}
P &operator*=(const P &r) {
first *= r.first;
second *= r.second;
return *this;
}
template <typename S>
P &operator*=(const S &r) {
first *= r, second *= r;
return *this;
}
P operator+(const P &r) const { return P(*this) += r; }
P operator-(const P &r) const { return P(*this) -= r; }
P operator*(const P &r) const { return P(*this) *= r; }
template <typename S>
P operator*(const S &r) const {
return P(*this) *= r;
}
P operator-() const { return P{-first, -second}; }
};
using pl = P<ll, ll>;
using pi = P<int, int>;
using vp = V<pl>;
constexpr int inf = 1001001001;
constexpr long long infLL = 4004004004004004004LL;
template <typename T>
int sz(const T &t) {
return t.size();
}
template <typename T, typename U>
inline bool amin(T &x, U y) {
return (y < x) ? (x = y, true) : false;
}
template <typename T, typename U>
inline bool amax(T &x, U y) {
return (x < y) ? (x = y, true) : false;
}
template <typename T>
inline T Max(const vector<T> &v) {
return *max_element(begin(v), end(v));
}
template <typename T>
inline T Min(const vector<T> &v) {
return *min_element(begin(v), end(v));
}
template <typename T>
inline long long Sum(const vector<T> &v) {
return accumulate(begin(v), end(v), 0LL);
}
template <typename T>
int lb(const vector<T> &v, const T &a) {
return lower_bound(begin(v), end(v), a) - begin(v);
}
template <typename T>
int ub(const vector<T> &v, const T &a) {
return upper_bound(begin(v), end(v), a) - begin(v);
}
constexpr long long TEN(int n) {
long long ret = 1, x = 10;
for (; n; x *= x, n >>= 1) ret *= (n & 1 ? x : 1);
return ret;
}
template <typename T, typename U>
pair<T, U> mkp(const T &t, const U &u) {
return make_pair(t, u);
}
template <typename T>
vector<T> mkrui(const vector<T> &v, bool rev = false) {
vector<T> ret(v.size() + 1);
if (rev) {
for (int i = int(v.size()) - 1; i >= 0; i--) ret[i] = v[i] + ret[i + 1];
} else {
for (int i = 0; i < int(v.size()); i++) ret[i + 1] = ret[i] + v[i];
}
return ret;
};
template <typename T>
vector<T> mkuni(const vector<T> &v) {
vector<T> ret(v);
sort(ret.begin(), ret.end());
ret.erase(unique(ret.begin(), ret.end()), ret.end());
return ret;
}
template <typename F>
vector<int> mkord(int N,F f) {
vector<int> ord(N);
iota(begin(ord), end(ord), 0);
sort(begin(ord), end(ord), f);
return ord;
}
template <typename T>
vector<int> mkinv(vector<T> &v) {
int max_val = *max_element(begin(v), end(v));
vector<int> inv(max_val + 1, -1);
for (int i = 0; i < (int)v.size(); i++) inv[v[i]] = i;
return inv;
}
vector<int> mkiota(int n) {
vector<int> ret(n);
iota(begin(ret), end(ret), 0);
return ret;
}
template <typename T>
T mkrev(const T &v) {
T w{v};
reverse(begin(w), end(w));
return w;
}
template <typename T>
bool nxp(vector<T> &v) {
return next_permutation(begin(v), end(v));
}
template <typename T>
using minpq = priority_queue<T, vector<T>, greater<T>>;
} // namespace Nyaan
// bit operation
namespace Nyaan {
__attribute__((target("popcnt"))) inline int popcnt(const u64 &a) {
return _mm_popcnt_u64(a);
}
inline int lsb(const u64 &a) { return a ? __builtin_ctzll(a) : 64; }
inline int ctz(const u64 &a) { return a ? __builtin_ctzll(a) : 64; }
inline int msb(const u64 &a) { return a ? 63 - __builtin_clzll(a) : -1; }
template <typename T>
inline int gbit(const T &a, int i) {
return (a >> i) & 1;
}
template <typename T>
inline void sbit(T &a, int i, bool b) {
if (gbit(a, i) != b) a ^= T(1) << i;
}
constexpr long long PW(int n) { return 1LL << n; }
constexpr long long MSK(int n) { return (1LL << n) - 1; }
} // namespace Nyaan
// inout
namespace Nyaan {
template <typename T, typename U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
os << p.first << " " << p.second;
return os;
}
template <typename T, typename U>
istream &operator>>(istream &is, pair<T, U> &p) {
is >> p.first >> p.second;
return is;
}
template <typename T>
ostream &operator<<(ostream &os, const vector<T> &v) {
int s = (int)v.size();
for (int i = 0; i < s; i++) os << (i ? " " : "") << v[i];
return os;
}
template <typename T>
istream &operator>>(istream &is, vector<T> &v) {
for (auto &x : v) is >> x;
return is;
}
istream &operator>>(istream &is, __int128_t &x) {
string S;
is >> S;
x = 0;
int flag = 0;
for (auto &c : S) {
if (c == '-') {
flag = true;
continue;
}
x *= 10;
x += c - '0';
}
if (flag) x = -x;
return is;
}
istream &operator>>(istream &is, __uint128_t &x) {
string S;
is >> S;
x = 0;
for (auto &c : S) {
x *= 10;
x += c - '0';
}
return is;
}
ostream &operator<<(ostream &os, __int128_t x) {
if (x == 0) return os << 0;
if (x < 0) os << '-', x = -x;
string S;
while (x) S.push_back('0' + x % 10), x /= 10;
reverse(begin(S), end(S));
return os << S;
}
ostream &operator<<(ostream &os, __uint128_t x) {
if (x == 0) return os << 0;
string S;
while (x) S.push_back('0' + x % 10), x /= 10;
reverse(begin(S), end(S));
return os << S;
}
void in() {}
template <typename T, class... U>
void in(T &t, U &...u) {
cin >> t;
in(u...);
}
void out() { cout << "\n"; }
template <typename T, class... U, char sep = ' '>
void out(const T &t, const U &...u) {
cout << t;
if (sizeof...(u)) cout << sep;
out(u...);
}
void outr() {}
template <typename T, class... U, char sep = ' '>
void outr(const T &t, const U &...u) {
cout << t;
outr(u...);
}
struct IoSetupNya {
IoSetupNya() {
cin.tie(nullptr);
ios::sync_with_stdio(false);
cout << fixed << setprecision(15);
cerr << fixed << setprecision(7);
}
} iosetupnya;
} // namespace Nyaan
// debug
#ifdef NyaanDebug
#define trc(...) (void(0))
#else
#define trc(...) (void(0))
#endif
#ifdef NyaanLocal
#define trc2(...) (void(0))
#else
#define trc2(...) (void(0))
#endif
// macro
#define each(x, v) for (auto&& x : v)
#define each2(x, y, v) for (auto&& [x, y] : v)
#define all(v) (v).begin(), (v).end()
#define rep(i, N) for (long long i = 0; i < (long long)(N); i++)
#define repr(i, N) for (long long i = (long long)(N)-1; i >= 0; i--)
#define rep1(i, N) for (long long i = 1; i <= (long long)(N); i++)
#define repr1(i, N) for (long long i = (N); (long long)(i) > 0; i--)
#define reg(i, a, b) for (long long i = (a); i < (b); i++)
#define regr(i, a, b) for (long long i = (b)-1; i >= (a); i--)
#define fi first
#define se second
#define ini(...) \
int __VA_ARGS__; \
in(__VA_ARGS__)
#define inl(...) \
long long __VA_ARGS__; \
in(__VA_ARGS__)
#define ins(...) \
string __VA_ARGS__; \
in(__VA_ARGS__)
#define in2(s, t) \
for (int i = 0; i < (int)s.size(); i++) { \
in(s[i], t[i]); \
}
#define in3(s, t, u) \
for (int i = 0; i < (int)s.size(); i++) { \
in(s[i], t[i], u[i]); \
}
#define in4(s, t, u, v) \
for (int i = 0; i < (int)s.size(); i++) { \
in(s[i], t[i], u[i], v[i]); \
}
#define die(...) \
do { \
Nyaan::out(__VA_ARGS__); \
return; \
} while (0)
namespace Nyaan {
void solve();
}
int main() { Nyaan::solve(); }
//
struct UnionFind {
vector<int> data;
UnionFind(int N) : data(N, -1) {}
int find(int k) { return data[k] < 0 ? k : data[k] = find(data[k]); }
int unite(int x, int y) {
if ((x = find(x)) == (y = find(y))) return false;
if (data[x] > data[y]) swap(x, y);
data[x] += data[y];
data[y] = x;
return true;
}
// f ... merge function
template<typename F>
int unite(int x, int y,const F &f) {
if ((x = find(x)) == (y = find(y))) return false;
if (data[x] > data[y]) swap(x, y);
data[x] += data[y];
data[y] = x;
f(x, y);
return true;
}
int size(int k) { return -data[find(k)]; }
int same(int x, int y) { return find(x) == find(y); }
};
/**
* @brief Union Find(Disjoint Set Union)
* @docs docs/data-structure/union-find.md
*/
//
namespace inner {
using i64 = long long;
using u64 = unsigned long long;
using u128 = __uint128_t;
template <int BASE_NUM = 2>
struct Hash : array<u64, BASE_NUM> {
using array<u64, BASE_NUM>::operator[];
static constexpr int n = BASE_NUM;
Hash() : array<u64, BASE_NUM>() {}
static constexpr u64 md = (1ull << 61) - 1;
constexpr static Hash set(const i64 &a) {
Hash res;
fill(begin(res), end(res), cast(a));
return res;
}
Hash &operator+=(const Hash &r) {
for (int i = 0; i < n; i++)
if (((*this)[i] += r[i]) >= md) (*this)[i] -= md;
return *this;
}
Hash &operator+=(const i64 &r) {
u64 s = cast(r);
for (int i = 0; i < n; i++)
if (((*this)[i] += s) >= md) (*this)[i] -= md;
return *this;
}
Hash &operator-=(const Hash &r) {
for (int i = 0; i < n; i++)
if (((*this)[i] += md - r[i]) >= md) (*this)[i] -= md;
return *this;
}
Hash &operator-=(const i64 &r) {
u64 s = cast(r);
for (int i = 0; i < n; i++)
if (((*this)[i] += md - s) >= md) (*this)[i] -= md;
return *this;
}
Hash &operator*=(const Hash &r) {
for (int i = 0; i < n; i++) (*this)[i] = modmul((*this)[i], r[i]);
return *this;
}
Hash &operator*=(const i64 &r) {
u64 s = cast(r);
for (int i = 0; i < n; i++) (*this)[i] = modmul((*this)[i], s);
return *this;
}
Hash operator+(const Hash &r) { return Hash(*this) += r; }
Hash operator+(const i64 &r) { return Hash(*this) += r; }
Hash operator-(const Hash &r) { return Hash(*this) -= r; }
Hash operator-(const i64 &r) { return Hash(*this) -= r; }
Hash operator*(const Hash &r) { return Hash(*this) *= r; }
Hash operator*(const i64 &r) { return Hash(*this) *= r; }
Hash operator-() const {
Hash res;
for (int i = 0; i < n; i++) res[i] = (*this)[i] == 0 ? 0 : md - (*this)[i];
return res;
}
friend Hash pfma(const Hash &a, const Hash &b, const Hash &c) {
Hash res;
for (int i = 0; i < n; i++) res[i] = modfma(a[i], b[i], c[i]);
return res;
}
friend Hash pfma(const Hash &a, const Hash &b, const i64 &c) {
Hash res;
u64 s = cast(c);
for (int i = 0; i < n; i++) res[i] = modfma(a[i], b[i], s);
return res;
}
Hash pow(long long e) {
Hash a{*this}, res{Hash::set(1)};
for (; e; a *= a, e >>= 1) {
if (e & 1) res *= a;
}
return res;
}
static Hash get_basis() {
static auto rand_time =
chrono::duration_cast<chrono::nanoseconds>(
chrono::high_resolution_clock::now().time_since_epoch())
.count();
static mt19937_64 rng(rand_time);
Hash h;
for (int i = 0; i < n; i++) {
while (isPrimitive(h[i] = rng() % (md - 1) + 1) == false)
;
}
return h;
}
private:
static u64 modpow(u64 a, u64 b) {
u64 r = 1;
for (a %= md; b; a = modmul(a, a), b >>= 1) r = modmul(r, a);
return r;
}
static bool isPrimitive(u64 x) {
for (auto &d : vector<u64>{2, 3, 5, 7, 11, 13, 31, 41, 61, 151, 331, 1321})
if (modpow(x, (md - 1) / d) <= 1) return false;
return true;
}
static inline constexpr u64 cast(const long long &a) {
return a < 0 ? a + md : a;
}
static inline constexpr u64 modmul(const u64 &a, const u64 &b) {
u128 ret = u128(a) * b;
ret = (ret & md) + (ret >> 61);
return ret >= md ? ret - md : ret;
}
static inline constexpr u64 modfma(const u64 &a, const u64 &b, const u64 &c) {
u128 ret = u128(a) * b + c;
ret = (ret & md) + (ret >> 61);
return ret >= md ? ret - md : ret;
}
};
} // namespace inner
/**
* @brief ハッシュ構造体
* @docs docs/inner/inner-hash.md
*/
template <typename Str, int BASE_NUM = 2>
struct RollingHash {
using Hash = inner::Hash<BASE_NUM>;
Str data;
vector<Hash> hs, pw;
int s;
static Hash basis;
RollingHash(const Str &S = Str()) { build(S); }
void build(const Str &S) {
data = S;
s = S.size();
hs.resize(s + 1);
pw.resize(s + 1);
pw[0] = Hash::set(1);
hs[0] = Hash::set(0);
for (int i = 1; i <= s; i++) {
pw[i] = pw[i - 1] * basis;
hs[i] = pfma(hs[i - 1], basis, S[i - 1]);
}
}
Hash get(int l, int r = -1) const {
if (r == -1) r = s;
return pfma(hs[l], -pw[r - l], hs[r]);
}
// T の hash を返す
static Hash get_hash(const Str &T) {
Hash ret = Hash::set(0);
for (int i = 0; i < (int)T.size(); i++) ret = pfma(ret, basis, T[i]);
return ret;
}
// a + b の hash を返す
// 引数 : a, b, b の長さ
static Hash unite(Hash a, Hash b, long long bsize) {
return pfma(a, basis.pow(bsize), b);
}
int find(Str &T, int lower = 0) const {
auto ths = get_hash(T);
for (int i = lower; i <= s - (int)T.size(); i++)
if (ths == get(i, i + (int)T.size())) return i;
return -1;
}
static int lcp(const RollingHash &a, const RollingHash &b, int al, int bl) {
int ok = 0, ng = min(a.size() - al, b.size() - bl) + 1;
while (ok + 1 < ng) {
int med = (ok + ng) / 2;
(a.get(al, med + al) == b.get(bl, med + bl) ? ok : ng) = med;
}
return ok;
}
static int strcmp(const RollingHash &a, const RollingHash &b, int al, int bl,
int ar = -1, int br = -1) {
if (ar == -1) ar = a.size();
if (br == -1) br = b.size();
int n = min<int>({lcp(a, b, al, bl), ar - al, br - bl});
return al + n == ar ? bl + n == br ? 0 : -1
: bl + n == br ? 1
: a.data[al + n] < b.data[bl + n] ? -1
: 1;
}
int size() const { return s; }
};
template <typename Str, int BASE_NUM>
typename RollingHash<Str, BASE_NUM>::Hash RollingHash<Str, BASE_NUM>::basis =
inner::Hash<BASE_NUM>::get_basis();
using roriha = RollingHash<string, 2>;
/**
* @brief Rolling Hash
* @docs docs/string/rolling-hash.md
*/
//
vector<int> factor_enumerate(int N) {
vector<int> lp(N + 1, 0);
if (N < 2) return lp;
vector<int> pr{2, 3};
for (int i = 2; i <= N; i += 2) lp[i] = 2;
for (int i = 3; i <= N; i += 6) lp[i] = 3;
for (int i = 5, d = 4; i <= N; i += d = 6 - d) {
if (lp[i] == 0) {
lp[i] = i;
pr.push_back(i);
}
for (int j = 2; j < (int)pr.size() && i * pr[j] <= N; ++j) {
lp[i * pr[j]] = pr[j];
if (pr[j] == lp[i]) break;
}
}
return lp;
}
template <int MAX>
vector<int> osak(int n) {
static vector<int> f = factor_enumerate(MAX);
vector<int> ret;
while (f[n]) ret.push_back(f[n]), n /= f[n];
return ret;
}
template <int MAX>
vector<pair<int, int>> osak_table(int n) {
static vector<int> f = factor_enumerate(MAX);
vector<pair<int, int>> v;
for (; f[n]; n /= f[n]) {
if (v.empty() || v.back().first != f[n]) {
v.emplace_back(f[n], 1);
} else {
v.back().second++;
}
}
return v;
}
template <int MAX>
vector<int> osak_divisors(int n) {
if(n == 0) return {};
if(n == 1) return vector<int>(1, 1);
auto p = osak_table<MAX>(n);
vector<int> ds;
auto dfs = [&](auto r, int i, int c) {
if (i == (int)p.size()) {
ds.push_back(c);
return;
}
for (int j = 0; j <= p[i].second; j++) {
r(r, i + 1, c);
c *= p[i].first;
}
};
dfs(dfs, 0, 1);
sort(begin(ds), end(ds));
return ds;
}
//
template <uint32_t mod>
struct LazyMontgomeryModInt {
using mint = LazyMontgomeryModInt;
using i32 = int32_t;
using u32 = uint32_t;
using u64 = uint64_t;
static constexpr u32 get_r() {
u32 ret = mod;
for (i32 i = 0; i < 4; ++i) ret *= 2 - mod * ret;
return ret;
}
static constexpr u32 r = get_r();
static constexpr u32 n2 = -u64(mod) % mod;
static_assert(r * mod == 1, "invalid, r * mod != 1");
static_assert(mod < (1 << 30), "invalid, mod >= 2 ^ 30");
static_assert((mod & 1) == 1, "invalid, mod % 2 == 0");
u32 a;
constexpr LazyMontgomeryModInt() : a(0) {}
constexpr LazyMontgomeryModInt(const int64_t &b)
: a(reduce(u64(b % mod + mod) * n2)){};
static constexpr u32 reduce(const u64 &b) {
return (b + u64(u32(b) * u32(-r)) * mod) >> 32;
}
constexpr mint &operator+=(const mint &b) {
if (i32(a += b.a - 2 * mod) < 0) a += 2 * mod;
return *this;
}
constexpr mint &operator-=(const mint &b) {
if (i32(a -= b.a) < 0) a += 2 * mod;
return *this;
}
constexpr mint &operator*=(const mint &b) {
a = reduce(u64(a) * b.a);
return *this;
}
constexpr mint &operator/=(const mint &b) {
*this *= b.inverse();
return *this;
}
constexpr mint operator+(const mint &b) const { return mint(*this) += b; }
constexpr mint operator-(const mint &b) const { return mint(*this) -= b; }
constexpr mint operator*(const mint &b) const { return mint(*this) *= b; }
constexpr mint operator/(const mint &b) const { return mint(*this) /= b; }
constexpr bool operator==(const mint &b) const {
return (a >= mod ? a - mod : a) == (b.a >= mod ? b.a - mod : b.a);
}
constexpr bool operator!=(const mint &b) const {
return (a >= mod ? a - mod : a) != (b.a >= mod ? b.a - mod : b.a);
}
constexpr mint operator-() const { return mint() - mint(*this); }
constexpr mint pow(u64 n) const {
mint ret(1), mul(*this);
while (n > 0) {
if (n & 1) ret *= mul;
mul *= mul;
n >>= 1;
}
return ret;
}
constexpr mint inverse() const { return pow(mod - 2); }
friend ostream &operator<<(ostream &os, const mint &b) {
return os << b.get();
}
friend istream &operator>>(istream &is, mint &b) {
int64_t t;
is >> t;
b = LazyMontgomeryModInt<mod>(t);
return (is);
}
constexpr u32 get() const {
u32 ret = reduce(a);
return ret >= mod ? ret - mod : ret;
}
static constexpr u32 get_mod() { return mod; }
};
template <typename T>
struct Binomial {
vector<T> f, g, h;
Binomial(int MAX = 0) {
assert(T::get_mod() != 0 && "Binomial<mint>()");
f.resize(1, T{1});
g.resize(1, T{1});
h.resize(1, T{1});
while (MAX >= (int)f.size()) extend();
}
void extend() {
int n = f.size();
int m = n * 2;
f.resize(m);
g.resize(m);
h.resize(m);
for (int i = n; i < m; i++) f[i] = f[i - 1] * T(i);
g[m - 1] = f[m - 1].inverse();
h[m - 1] = g[m - 1] * f[m - 2];
for (int i = m - 2; i >= n; i--) {
g[i] = g[i + 1] * T(i + 1);
h[i] = g[i] * f[i - 1];
}
}
T fac(int i) {
if (i < 0) return T(0);
while (i >= (int)f.size()) extend();
return f[i];
}
T finv(int i) {
if (i < 0) return T(0);
while (i >= (int)g.size()) extend();
return g[i];
}
T inv(int i) {
if (i < 0) return -inv(-i);
while (i >= (int)h.size()) extend();
return h[i];
}
T C(int n, int r) {
if (n < 0 || n < r || r < 0) return T(0);
return fac(n) * finv(n - r) * finv(r);
}
inline T operator()(int n, int r) { return C(n, r); }
template <typename I>
T multinomial(const vector<I>& r) {
static_assert(is_integral<I>::value == true);
int n = 0;
for (auto& x : r) {
if (x < 0) return T(0);
n += x;
}
T res = fac(n);
for (auto& x : r) res *= finv(x);
return res;
}
template <typename I>
T operator()(const vector<I>& r) {
return multinomial(r);
}
T C_naive(int n, int r) {
if (n < 0 || n < r || r < 0) return T(0);
T ret = T(1);
r = min(r, n - r);
for (int i = 1; i <= r; ++i) ret *= inv(i) * (n--);
return ret;
}
T P(int n, int r) {
if (n < 0 || n < r || r < 0) return T(0);
return fac(n) * finv(n - r);
}
// [x^r] 1 / (1-x)^n
T H(int n, int r) {
if (n < 0 || r < 0) return T(0);
return r == 0 ? 1 : C(n + r - 1, r);
}
};
//
using namespace Nyaan;
using mint = LazyMontgomeryModInt<998244353>;
// using mint = LazyMontgomeryModInt<1000000007>;
using vm = vector<mint>;
using vvm = vector<vm>;
Binomial<mint> C;
using namespace Nyaan;
template <typename T>
vector<vector<T>> transpose(const vector<vector<T>>& v) {
if (v.empty()) return {};
int n = v.size(), m = v[0].size();
vector<vector<T>> res(m, vector<T>(n));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
res[j][i] = v[i][j];
}
}
return res;
}
vector<vector<int>> cycle_decomposition(vector<int> c) {
int n = c.size();
assert(0 <= Min(c) and Max(c) < n);
vector<vector<int>> res;
vector<int> vis(n);
for (int i = 0; i < n; i++) {
if (vis[i]) continue;
vector<int> cur;
for (int j = i;; j = c[j]) {
if (vis[j]) break;
vis[j] = true;
cur.push_back(j);
}
res.push_back(cur);
}
return res;
}
void q() {
ini(H, W);
vvi A(H, vi(W));
in(A);
vi ch, cw;
rep(s, 2) for (int i = s; i < H; i += 2) ch.push_back(i);
rep(s, 2) for (int i = s; i < W; i += 2) cw.push_back(i);
ch = mkinv(ch);
cw = mkinv(cw);
trc(ch);
trc(cw);
auto cs1 = cycle_decomposition(ch);
auto cs2 = cycle_decomposition(cw);
trc(cs1);
trc(cs2);
mint ans = 1;
rep(_, 2) {
each(c1, cs1) {
map<int, int> fac;
if (sz(c1) != 1) continue;
each(c2, cs2) {
if (sz(c2) == 1) continue;
int t = sz(c2);
vi v;
each(j, c2) v.push_back(A[c1[0]][j]);
rep(i, t) v.push_back(v[i]);
RollingHash<vi, 2> rv{v};
int shuki = t;
auto h1 = rv.get(0, t);
each(d, osak_divisors<3030303>(t)) {
auto h2 = rv.get(d, t + d);
if (h1 == h2) {
shuki = d;
break;
}
}
trc(v, shuki);
each2(p, e, osak_table<3030303>(shuki)) { fac[p] = max(fac[p], e); }
}
trc(c1, fac);
each2(p, e, fac) ans *= mint{p}.pow(e);
}
swap(H, W);
A = transpose(A);
swap(ch, cw);
swap(cs1, cs2);
}
{
vvi cs3, cs4;
each(c1, cs1) if (sz(c1) > 1) cs3.push_back(c1);
each(c2, cs2) if (sz(c2) > 1) cs4.push_back(c2);
swap(cs3, cs1), swap(cs4, cs2);
}
trc(cs1, cs2);
vvi rev(sz(cs1), vi(sz(cs2)));
rep(i, sz(cs1)) rep(j, sz(cs2)) {
auto& c1 = cs1[i];
auto& c2 = cs2[j];
int s = sz(c1), t = sz(c2);
map<int, int> mp;
rep(ii, s) rep(jj, t) mp[A[c1[ii]][c2[jj]]]++;
vi shu;
each2(k, v, mp) shu.push_back(v);
ans *= C.multinomial(shu);
if (Max(shu) == 1) {
ans *= C.inv(2);
rev[i][j] = 1;
}
}
trc(ans);
trc(cs1, cs2);
// 1 の行
rep(_, 2) {
rep(i, sz(cs1)) {
if (sz(cs1[i]) % 2 != 1) continue;
int c = 0;
rep(j, sz(cs2)) {
if (sz(cs2[j]) % 2 == 0 and rev[i][j]) c = 1;
}
if (c) ans *= 2;
}
swap(cs1, cs2);
transpose(rev);
}
trc(ans);
// 両方 0
{
UnionFind uf(sz(cs1) + sz(cs2));
rep(i, sz(cs1)) rep(j, sz(cs2)) {
if (sz(cs1[i]) % 2 == 0 and sz(cs2[j]) % 2 == 0) {
if (rev[i][j]) {
if (!uf.same(i, sz(cs1) + j)) {
ans *= 2;
uf.unite(i, sz(cs1) + j);
}
}
}
}
}
out(ans);
}
void Nyaan::solve() {
int t = 1;
in(t);
while (t--) q();
}
Details
Tip: Click on the bar to expand more detailed information
Test #1:
score: 100
Accepted
time: 8ms
memory: 15896kb
input:
2 4 4 1 2 3 4 3 4 1 2 1 2 4 1 4 3 3 2 3 9 1 8 1 1 8 1 1 8 1 1 8 8 8 8 8 8 8 1 1 1 1 8 8 8 1 1 1
output:
96 6336
result:
ok 2 number(s): "96 6336"
Test #2:
score: 0
Accepted
time: 7ms
memory: 16028kb
input:
1 18 16 8 8 1 1 8 8 8 1 8 8 8 1 8 8 8 1 8 1 8 1 8 1 1 1 8 1 1 1 8 1 1 1 8 8 8 1 8 8 8 1 8 8 8 1 8 8 8 1 8 8 1 1 8 1 1 1 8 1 1 1 8 1 1 1 8 1 8 1 8 8 8 1 8 1 1 1 8 8 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 8 8 1 1 8 8 8 1 8 8 8 1 7 7 7 1 8 1 8 1 8 1 1 1 8 1 1 1 1 1 7 1 8 8 8 1 8 8 8 1 8 8 8 1 1 7 7 1 8 8 ...
output:
690561281
result:
ok 1 number(s): "690561281"
Test #3:
score: -100
Runtime Error
input:
71117 7 8 2868391 1228870 2892937 349733 664891 1675356 1981526 762573 2892937 2892937 664891 1228870 959280 762573 664891 959280 349733 250147 1675356 349733 349733 762573 1675356 250147 1675356 959280 664891 250147 250147 250147 2868391 959280 1675356 664891 250147 1228870 1981526 250147 2868391 2...