diff --git a/algorithms/math/chinese_remainder_theorem.cpp b/algorithms/math/chinese_remainder_theorem.cpp index a28c5d27baf5f8e2dd20e88624eb6216869e041c..8e3f5de86a5a1a0d87be80ef13282ec9bc8cb97c 100644 --- a/algorithms/math/chinese_remainder_theorem.cpp +++ b/algorithms/math/chinese_remainder_theorem.cpp @@ -16,7 +16,10 @@ /// - It is very easy to get overflow, since the $LCM$ is computed from /// all $m_i$, BigInt or Python should be considered if inputs are too large -ll norm(ll a, ll b) { return (a + b) % b; } +ll norm(ll a, ll b) { + a %= b; + return (a < 0) ? a + b : a; +} pair<ll,ll> crt_single(ll a, ll n, ll b, ll m) { ans_t e = ext_gcd(n, m); @@ -24,24 +27,24 @@ pair<ll,ll> crt_single(ll a, ll n, ll b, ll m) { if ((a - b) % e.d != 0) return {-1,-1}; // No solution - ll ans = norm(a + e.x*(b-a) / e.d % (m/e.d)*n, n *m / e.d); - ll lcm = (n*m) / e.d; + ll lcm = (m/e.d) * n; + ll ans = norm(a + e.x*(b-a) / e.d % (m/e.d)*n, lcm); return {norm(ans, lcm), lcm}; } ll crt(vector<ll> a, vector<ll> m) { - ll res = a[0]; + ll ans = a[0]; ll lcm = m[0]; - int t = s.size(); + int t = a.size(); for (int i = 1; i < t; ++i) { - auto ss = crt(res, lcm, a[i], m[i]); + auto ss = crt_single(ans, lcm, a[i], m[i]); if (ss.fi == -1) return -1; // No solution - res = ss.fi; + ans = ss.fi; lcm = ss.se; } - return res; + return ans; } diff --git a/caderno.pdf b/caderno.pdf index aa8baf52d7e241dfcb6f1668061ae0b42606296c..fc4729e8045c647ef5f437a46b407711e31e7563 100644 Binary files a/caderno.pdf and b/caderno.pdf differ diff --git a/contests/ICPC_LA18/F.cpp b/contests/ICPC_LA18/F.cpp index 48d59be9b56b74fac067afb16a1e854b47170a42..712db75f6c92a968fa4cb14392dbc3e876affcf8 100644 --- a/contests/ICPC_LA18/F.cpp +++ b/contests/ICPC_LA18/F.cpp @@ -19,435 +19,87 @@ using namespace std; using ll = long long; using ii = pair<ll,ll>; -vector<ll> karatsuba(const vector<ll> &a, - const vector<ll> &b) -{ - int n = a.size(); - vector<ll> res(n + n); +struct ans_t { ll x, y, d; }; - if (n <= 32) { - for (int i = 0; i < n; i++) - for (int j = 0; j < n; j++) - res[i + j] += a[i] * b[j]; - - return res; - } - - int k = n >> 1; - vector<ll> a1(a.begin(), a.begin() + k); - vector<ll> a2(a.begin() + k, a.end()); - vector<ll> b1(b.begin(), b.begin() + k); - vector<ll> b2(b.begin() + k, b.end()); - - vector<ll> a1b1 = karatsuba(a1, b1); - vector<ll> a2b2 = karatsuba(a2, b2); - - for (int i = 0; i < k; i++) - a2[i] += a1[i]; - for (int i = 0; i < k; i++) - b2[i] += b1[i]; - - vector<ll> r = karatsuba(a2, b2); - for (int i = 0; i < a1b1.size(); i++) - r[i] -= a1b1[i]; - for (int i = 0; i < a2b2.size(); i++) - r[i] -= a2b2[i]; - - for (int i = 0; i < r.size(); i++) - res[i + k] += r[i]; - for (int i = 0; i < a1b1.size(); i++) - res[i] += a1b1[i]; - for (int i = 0; i < a2b2.size(); i++) - res[i + n] += a2b2[i]; - - return res; -} - -const int base = 1000000000; -const int base_d = 9; - -struct BigInt { - int sign; - vector<int> num; - - BigInt() : sign(1) {} - BigInt(ll x) { *this = x; } - - void operator=(const BigInt &x) { - sign = x.sign; - num = x.num; - } - - void operator=(ll x) { - sign = 1; - if (x < 0) sign = -1, x = -x; - for (; x > 0; x /= base) - pb(x % base); - } - - BigInt operator+(const BigInt &x) const { - if (sign != x.sign) return *this - (-x); - - int carry = 0; - BigInt res = x; - - for (int i = 0; i < max(size(), x.size()) || carry; ++i) { - if (i == (int) res.size()) - res.push_back(0); - - res[i] += carry + (i < size() ? num[i] : 0); - carry = res[i] >= base; - if (carry) res[i] -= base; - } - - return res; - } - - BigInt operator-(const BigInt &x) const { - if (sign != x.sign) return *this + (-x); - if (abs() < x.abs()) return -(x - *this); - - int carry = 0; - BigInt res = *this; - - for (int i = 0; i < x.size() || carry; ++i) { - res[i] -= carry + (i < x.size() ? x[i] : 0); - carry = res[i] < 0; - if (carry) res[i] += base; - } - - res.trim(); - return res; - } - - void operator*=(int x) { - if (x < 0) sign = -sign, x = -x; - - int carry = 0; - for (int i = 0; i < size() || carry; ++i) { - if (i == size()) pb(0); - ll cur = num[i] * (ll) x + carry; - - carry = (int) (cur / base); - num[i] = (int) (cur % base); - } - - trim(); - } - - BigInt operator*(int x) const { - BigInt res = *this; - res *= x; - return res; - } - - friend pair<BigInt, BigInt> divmod(const BigInt &a1, - const BigInt &b1) - { - int norm = base / (b1.back() + 1); - BigInt a = a1.abs() * norm; - BigInt b = b1.abs() * norm; - BigInt q, r; - q.resize(a.size()); - - for (int i = a.size() - 1; i >= 0; i--) { - r *= base; - r += a[i]; - - int s1 = r.size() <= b.size() ? 0 : r[b.size()]; - int s2 = r.size() <= b.size() - 1 ? 0 : r[b.size() - 1]; - int d = ((ll) base * s1 + s2) / b.back(); - - r -= b * d; - while (r < 0) r += b, --d; - q[i] = d; - } - - q.sign = a1.sign * b1.sign; - r.sign = a1.sign; - q.trim(); r.trim(); - - return make_pair(q, r / norm); - } - - BigInt operator/(const BigInt &x) const { - return divmod(*this, x).fi; - } - - BigInt operator%(const BigInt &x) const { - return divmod(*this, x).se; - } - - void operator/=(int x) { - if (x < 0) sign = -sign, x = -x; - - for (int i = size() - 1, rem = 0; i >= 0; --i) { - ll cur = num[i] + rem * (ll) base; - num[i] = (int) (cur / x); - rem = (int) (cur % x); - } - - trim(); - } - - BigInt operator/(int x) const { - BigInt res = *this; - res /= x; - return res; - } - - int operator%(int x) const { - if (x < 0) x = -x; - - int m = 0; - for (int i = size() - 1; i >= 0; --i) - m = (num[i] + m * (ll) base) % x; - - return m * sign; - } - - void operator+=(const BigInt &x) { *this = *this + x; } - void operator-=(const BigInt &x) { *this = *this - x; } - void operator*=(const BigInt &x) { *this = *this * x; } - void operator/=(const BigInt &x) { *this = *this / x; } - - bool operator<(const BigInt &x) const { - if (sign != x.sign) - return sign < x.sign; - - if (size() != x.size()) - return size() * sign < x.size() * x.sign; - - for (int i = size() - 1; i >= 0; i--) - if (num[i] != x[i]) - return num[i] * sign < x[i] * sign; - - return false; - } - - bool operator>(const BigInt &x) const { - return x < *this; - } - bool operator<=(const BigInt &x) const { - return !(x < *this); - } - bool operator>=(const BigInt &x) const { - return !(*this < x); - } - bool operator==(const BigInt &x) const { - return !(*this < x) && !(x < *this); - } - bool operator!=(const BigInt &x) const { - return *this < x || x < *this; - } - - void trim() { - while (!empty() && !back()) pop_back(); - if (empty()) sign = 1; - } - - bool is_zero() const { - return empty() || (size() == 1 && !num[0]); - } - - BigInt operator-() const { - BigInt res = *this; - res.sign = -sign; - return res; - } - - BigInt abs() const { - BigInt res = *this; - res.sign *= res.sign; - return res; - } - - ll to_long() const { - ll res = 0; - for (int i = size() - 1; i >= 0; i--) - res = res * base + num[i]; - return res * sign; - } - - void read(const string &s) { - sign = 1; - num.clear(); - - int pos = 0; - while (pos < s.size() && - (s[pos] == '-' || s[pos] == '+')) { - if (s[pos] == '-') - sign = -sign; - ++pos; - } - - for (int i = s.size() - 1; i >= pos; i -= base_d) { - int x = 0; - for (int j = max(pos, i - base_d + 1); j <= i; j++) - x = x * 10 + s[j] - '0'; - num.push_back(x); - } - - trim(); - } - - friend istream& operator>>(istream &stream, BigInt &v) { - string s; stream >> s; - v.read(s); - return stream; - } - - friend ostream& operator<<(ostream &stream, const BigInt &x) { - if (x.sign == -1) - stream << '-'; - - stream << (x.empty() ? 0 : x.back()); - for (int i = x.size() - 2; i >= 0; --i) - stream << setw(base_d) << setfill('0') << x.num[i]; - - return stream; - } - - static vector<int> convert_base( - const vector<int> &a, - int oldd, int newd) { - vector<ll> p(max(oldd, newd) + 1); - p[0] = 1; - for (int i = 1; i < p.size(); i++) - p[i] = p[i - 1] * 10; - - ll cur = 0; - int curd = 0; - vector<int> res; - - for (int i = 0; i < a.size(); i++) { - cur += a[i] * p[curd]; - curd += oldd; - - while (curd >= newd) { - res.pb(int(cur % p[newd])); - cur /= p[newd]; - curd -= newd; - } - } - - res.pb((int) cur); - while (!res.empty() && !res.back()) - res.pop_back(); - return res; - } - - BigInt operator*(const BigInt &x) const { - vector<int> a6 = convert_base(this->num, base_d, 6); - vector<int> b6 = convert_base(x.num, base_d, 6); - - vector<ll> a(all(a6)); - vector<ll> b(all(b6)); - - while (a.size() < b.size()) a.pb(0); - while (b.size() < a.size()) b.pb(0); - while (a.size() & (a.size() - 1)) - a.pb(0), b.pb(0); - - vector<ll> c = karatsuba(a, b); - - BigInt res; - int carry = 0; - res.sign = sign * x.sign; - - for (int i = 0; i < c.size(); i++) { - ll cur = c[i] + carry; - res.pb((int) (cur % 1000000)); - carry = (int) (cur / 1000000); - } - - res.num = convert_base(res.num, 6, base_d); - res.trim(); - return res; - } - - // Handles vector operations. - int back() const { return num.back(); } - bool empty() const { return num.empty(); } - size_t size() const { return num.size(); } - - void pop_back() { num.pop_back(); } - void resize(int x) { num.resize(x); } - void push_back(int x) { num.push_back(x); } - - int &operator[](int i) { return num[i]; } - int operator[](int i) const { return num[i]; } -}; - -using pb = pair<BigInt,BigInt>; - -template <typename T> -struct ans_t { T x, y, d; }; - -template <typename T> -ans_t<T> ext_gcd(T a, T b) { +ans_t ext_gcd(ll a, ll b) { if (a == 0) return {0, 1, b}; - ans_t<T> e = ext_gcd(b % a, a); + ans_t e = ext_gcd(b % a, a); return {e.y - (b/a) * e.x, e.x, e.d}; } -template <typename T> -T norm(T a, T b) { - return (a + b) % b; +ll norm(ll a, ll b) { + a %= b; + return (a < 0) ? a + b : a; } -template <typename T> -pb crt(T a, T n, T b, T m) { - ans_t<T> e = ext_gcd(n, m); +pair<ll,ll> crt_single(ll a, ll n, ll b, ll m) { + ans_t e = ext_gcd(n, m); if ((a - b) % e.d != 0) return {-1,-1}; - T ans = norm(a + e.x*(b-a) / e.d % (m/e.d)*n, n *m / e.d); - T lcm = (n*m) / e.d; + ll lcm = (m/e.d) * n; + ll ans = norm(a + e.x*(b-a) / e.d % (m/e.d)*n, lcm); return {norm(ans, lcm), lcm}; } +ll crt(vector<ll> a, vector<ll> m) { + ll ans = a[0]; + ll lcm = m[0]; + + int t = a.size(); + for (int i = 1; i < t; ++i) { + auto ss = crt_single(ans, lcm, a[i], m[i]); + if (ss.fi == -1) + return -1; + + ans = ss.fi; + lcm = ss.se; + } + + return ans; +} + int main() { ios::sync_with_stdio(0); cin.tie(0); int b, z; cin >> b >> z; vector<vector<int>> mat(b, vector<int>(z+1)); - for (int i = 0; i < b; ++i) - for (int j = 0; j <= z; ++j) - cin >> mat[i][j]; - vector<vector<int>> time(z+1, vector<int>(501)); + vector<vector<ll>> a(z + 1, vector<ll>(b, -1)); + vector<vector<ll>> m(z + 1, vector<ll>(b, -1)); + + for (auto &i : mat) + for (auto &j : i) cin >> j; + for (int i = 0; i < b; ++i) { int curr = mat[i][0]; time[curr][0] |= (1 << i); + for (int t = 1; t <= 500; ++t) { curr = mat[i][curr]; time[curr][t] |= (1 << i); } } - vector<vector<int>> a(z + 1, vector<int>(b, -1)); - vector<vector<int>> m(z + 1, vector<int>(b, -1)); for (int i = 1; i <= z; ++i) { for (int t = 0; t <= 500; ++t) { if (time[i][t] == (1 << b) - 1) return cout << i << " " << t << ende, 0; - for (int j = 0; j < b; ++j) { + for (int j = 0; j < b; ++j) if (time[i][t] & (1 << j)) { if (a[i][j] == -1) a[i][j] = t; else if (m[i][j] == -1) m[i][j] = t - a[i][j]; } - } } } - int zoo = 0; - BigInt ans = llinf*2; + ll zoo = 0; + ll ans = llinf*2; for (int i = 1; i <= z; ++i) { bool poss = true; for (int j = 0; j < b; ++j) @@ -456,24 +108,14 @@ int main() { break; } - if (!poss) continue; - - BigInt res = a[i][0]; - BigInt lcm = m[i][0]; - for (int j = 1; j < b; ++j) { - pb ss = crt(res, lcm, BigInt(a[i][j]), BigInt(m[i][j])); - if (ss.fi == -1) { - poss = false; - break; - } - - res = ss.fi; - lcm = ss.se; - } + if (!poss) + continue; - if (!poss) continue; + ll res = crt(a[i], m[i]); + if (res == -1) + continue; else { - if (ans > res) + if (ans > res && res > 0) zoo = i, ans = res; } }