QOJ.ac

QOJ

IDSubmission IDProblemHackerOwnerResultSubmit timeJudge time
#848#348485#8340. 3 Sumhzjoiinegucup-team1191Success!2024-09-20 10:20:112024-09-20 10:20:11

Details

Extra Test:

Runtime Error

input:

480 1473
883764032415038184006695299756989764048611671833138462208200123938159973478111621054950522219396561622102295676518419558194485698772507102772522845575295444190970700456491980944517708654278033088380407759998739824688416191760411336369898925923400221258517278345518890307001382204902882372159...

output:


result:


IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#348485#8340. 3 Sumucup-team1191#RE 103ms13312kbC++2019.3kb2024-03-09 18:53:502024-10-13 18:48:22

answer

/*
    author:  Maksim1744
    created: 09.03.2024 12:03:07
*/

#include "bits/stdc++.h"

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;

using ll = long long;
using ld = long double;

#define mp   make_pair
#define pb   push_back
#define eb   emplace_back

#define sum(a)     ( accumulate ((a).begin(), (a).end(), 0ll))
#define mine(a)    (*min_element((a).begin(), (a).end()))
#define maxe(a)    (*max_element((a).begin(), (a).end()))
#define mini(a)    ( min_element((a).begin(), (a).end()) - (a).begin())
#define maxi(a)    ( max_element((a).begin(), (a).end()) - (a).begin())
#define lowb(a, x) ( lower_bound((a).begin(), (a).end(), (x)) - (a).begin())
#define uppb(a, x) ( upper_bound((a).begin(), (a).end(), (x)) - (a).begin())

template<typename T>             vector<T>& operator--            (vector<T> &v){for (auto& i : v) --i;            return  v;}
template<typename T>             vector<T>& operator++            (vector<T> &v){for (auto& i : v) ++i;            return  v;}
template<typename T>             istream& operator>>(istream& is,  vector<T> &v){for (auto& i : v) is >> i;        return is;}
template<typename T>             ostream& operator<<(ostream& os,  vector<T>  v){for (auto& i : v) os << i << ' '; return os;}
template<typename T, typename U> pair<T,U>& operator--           (pair<T, U> &p){--p.first; --p.second;            return  p;}
template<typename T, typename U> pair<T,U>& operator++           (pair<T, U> &p){++p.first; ++p.second;            return  p;}
template<typename T, typename U> istream& operator>>(istream& is, pair<T, U> &p){is >> p.first >> p.second;        return is;}
template<typename T, typename U> ostream& operator<<(ostream& os, pair<T, U>  p){os << p.first << ' ' << p.second; return os;}
template<typename T, typename U> pair<T,U> operator-(pair<T,U> a, pair<T,U> b){return mp(a.first-b.first, a.second-b.second);}
template<typename T, typename U> pair<T,U> operator+(pair<T,U> a, pair<T,U> b){return mp(a.first+b.first, a.second+b.second);}
template<typename T, typename U> void umin(T& a, U b){if (a > b) a = b;}
template<typename T, typename U> void umax(T& a, U b){if (a < b) a = b;}

#ifdef HOME
#define SHOW_COLORS
#include "/mnt/c/Libs/tools/print.cpp"
#else
#define show(...) void(0)
#define debugf(fun)   fun
#define debugv(var)   var
#define mclock    void(0)
#define shows     void(0)
#define debug  if (false)
#define OSTREAM(...)    ;
#define OSTREAM0(...)   ;
#endif

const int basen = 18;
const ll base = 1e18;

// uncomment to multiply large numbers with fft
// basen should be even, at most 8
// with doubles in fft and basen = 8 works up to Big.v.size() = 1e6 (but fails for 1e6 + 5e4)
// #define BIGINT_USE_FFT

// division works in n^2 * log(base), where n = Big.v.size()

using T = ll;

array<ll, 19> pow10;

struct Big {
    vector<ll> v;
    bool minus = false;

    Big() {}
    Big(long long k) {
        if (k < 0) {
            minus = true;
            k = -k;
        }
        while (k) {
            v.push_back(k % base);
            k /= base;
        }
    }
    Big(string s) {
        if (s[0] == '-') {
            s.erase(s.begin());
            minus = true;
        }
        reverse(s.begin(), s.end());
        while (s.size() % basen != 0)
            s.push_back('0');
        reverse(s.begin(), s.end());
        for (int i = 0; i < s.size(); i += basen)
            v.push_back(stoll(s.substr(i, basen)));
        reverse(v.begin(), v.end());
        norm();
    }

    void modk(int k) {
        auto push_at = [&](int i) {
            while (i + 1 < v.size() && v[i] >= base) {
                while (v[i] >= base) {
                    v[i] -= base;
                    v[i + 1]++;
                }
                ++i;
            }
        };
        if (k <= basen) {
            while (v.size() > 1) {
                v.back() %= pow10[k] - 1;
                v[v.size() - 2] += v.back() * pow10[basen - k];
                v.back() = 0;
                push_at(v.size() - 2);
                if (v.back() == 0) v.pop_back();
            }
            norm();
            v[0] %= pow10[k] - 1;
            return;
        }
        while (v.size() > k / basen + 1) {
            ll x = v.back();
            v.back() -= x;
            int add_at = ((int)v.size() - 1) * basen % k;
            if (add_at % basen == 0) {
                v[add_at / basen] += x;
                push_at(add_at / basen);
            } else {
                v[add_at / basen] += pow10[add_at % basen] * (x % pow10[basen - add_at % basen]);
                v[add_at / basen + 1] += x / pow10[basen - add_at % basen];
                push_at(add_at / basen);
                push_at(add_at / basen + 1);
            }
            if (v.back() == 0) {
                v.pop_back();
            }
        }
        while (v.size() == k / basen + 1 && v.back() >= pow10[k - (v.size() - 1) * basen]) {
            ll x = v.back() / pow10[k - (v.size() - 1) * basen];
            v.back() %= pow10[k - (v.size() - 1) * basen];
            v[0] += x;
            push_at(0);
        }
        bool is0 = true;
        for (int i = 0; i + 1 < v.size(); ++i) {
            if (v[i] != pow10[basen] - 1) {
                is0 = false;
                break;
            }
        }
        if (v.back() != pow10[k - basen * (v.size() - 1)] - 1) {
            is0 = false;
        }
        if (is0) {
            v = {0};
        }
        norm();
    }

    void mulint(int x) {
        for (ll& u : v)
            u *= x;
        v.pb(0);
        for (int i = 0; i + 1 < v.size(); ++i) {
            v[i + 1] += v[i] / base;
            v[i] %= base;
        }
        norm();
    }

    int modint(int x) {
        ll basemod = base % x;
        ll ans = 0;
        ll pw = 1;
        for (ll u : v) {
            ans = (ans + u % x * pw) % x;
            pw = (pw * basemod) % x;
        }
        return ans;
    }

    Big &operator += (const Big &other) {
        if (minus == other.minus) {
            _add_(v, other.v);
        } else {
            if (_comp_(other.v, v)) {
                _sub_(v, other.v);
            } else {
                _sub2_(v, other.v);
                minus ^= 1;
            }
        }
        norm();
        return *this;
    }
    Big operator + (const Big &other) const {
        auto res = *this;
        return res += other;
    }

    Big operator - () const {
        Big res = *this;
        if (!v.empty()) res.minus ^= 1;
        return res;
    }
    Big &operator -= (const Big &other) {
        return *this += -other;
    }
    Big operator - (const Big &other) const {
        auto res = *this;
        return res -= other;
    }

    Big operator * (const Big &other) const {
        if (v.empty() || other.v.empty()) return 0;
        Big res;
        res.v = _mult_(v, other.v);
        res.minus = minus ^ other.minus;
        return res;
    }
    Big &operator *= (const Big &other) {
        return *this = *this * other;
    }

    Big operator / (const Big &other) const {
        Big res;
        res.v = _div_(v, other.v).first;
        res.minus = minus ^ other.minus;
        res.norm();
        return res;
    }
    Big &operator /= (const Big &other) {
        return *this = *this / other;
    }

    Big operator % (const Big &other) const {
        Big res;
        res.v = _div_(v, other.v).second;
        res.minus = minus ^ other.minus;
        res.norm();
        return res;
    }
    Big &operator %= (const Big &other) {
        return *this = *this % other;
    }

    int operator % (int m) const {
        long long p = 1;
        long long res = 0;
        for (int k : v) {
            res += k * p % m;
            p = p * base % m;
        }
        return res % m;
    }

    void norm() {
        while (!v.empty() && v.back() == 0)
            v.pop_back();
        if (v.empty()) {
            minus = false;
            v.pb(0);
        }
    }

    bool operator < (const Big &other) const {
        if (minus != other.minus) return minus;
        if (minus) return _comp_(other.v, v);
        else return _comp_(v, other.v);
    }
    bool operator > (const Big &other) const {
        return other < *this;
    }
    bool operator <= (const Big &other) const {
        return !(other < *this);
    }
    bool operator >= (const Big &other) const {
        return !(*this < other);
    }

    bool operator == (const Big &other) const {
        return minus == other.minus && v == other.v;
    }
    bool operator != (const Big &other) const {
        return !(*this == other);
    }

  private:
    static void _sub_(vector<T> &a, const vector<T> &b) {
        a.resize(max(a.size(), b.size()) + 1, 0);
        for (int i = 0; i < b.size(); ++i)
            a[i] -= b[i];
        for (int i = 0; i + 1 < b.size() || a[i] < 0; ++i) {
            if (a[i] < 0) {
                a[i] += base;
                --a[i + 1];
            }
        }
        assert(a.back() >= 0);
        while (!a.empty() && a.back() == 0)
            a.pop_back();
    }

    static void _sub2_(vector<T> &a, const vector<T> &b) {
        a.resize(max(a.size(), b.size()) + 1, 0);
        for (int i = 0; i < a.size(); ++i)
            a[i] = (i < b.size() ? b[i] : 0) - a[i];
        for (int i = 0; i + 1 < a.size(); ++i) {
            if (a[i] < 0) {
                a[i] += base;
                --a[i + 1];
            }
        }
        assert(a.back() >= 0);
        while (!a.empty() && a.back() == 0)
            a.pop_back();
    }

    static void _add_(vector<T> &a, const vector<T> &b) {
        a.resize(max(a.size(), b.size()) + 1, 0);
        for (int i = 0; i < b.size(); ++i)
            a[i] += b[i];
        for (int i = 0; i + 1 < b.size() || a[i] >= base; ++i) {
            if (a[i] >= base) {
                a[i] -= base;
                ++a[i + 1];
            }
        }
        while (!a.empty() && a.back() == 0)
            a.pop_back();
    }

    static bool _comp_(const vector<T> &a, const vector<T> &b) {
        if (a.size() != b.size())
            return a.size() < b.size();
        for (int i = (int)a.size() - 1; i >= 0; --i)
            if (a[i] != b[i])
                return a[i] < b[i];
        return false;
    }

    static vector<T> _mult_(const vector<T> &a, const vector<T> &b) {
        #ifdef BIGINT_USE_FFT
        // tested on a.v.size() = 1e6, b.v.size() = C, fft is better on C > ~500 : https://ideone.com/kSYLd8
        // if a.v.size() = b.v.size() = C, it's 380 : https://ideone.com/MJTo1Y
        if (min(a.size(), b.size()) > 380) {
            return _fft_mult_(a, b);
        }
        #endif

        return _slow_mult_(a, b);
    }

    static vector<T> _slow_mult_(const vector<T> &a, const vector<T> &b) {
        vector<long long> tmp(a.size() + b.size() + 1, 0);
        for (int i = 0; i < a.size(); ++i) {
            for (int j = 0; j < b.size(); ++j) {
                long long prod = 1ll * a[i] * b[j];
                long long div = prod / base;
                tmp[i + j] += prod - base * div;
                tmp[i + j + 1] += div;
            }
        }
        for (int i = 0; i + 1 < tmp.size(); ++i) {
            long long div = tmp[i] / base;
            tmp[i + 1] += div;
            tmp[i] -= div * base;
        }
        while (!tmp.empty() && tmp.back() == 0)
            tmp.pop_back();
        return vector<T>(tmp.begin(), tmp.end());
    }

    #ifdef BIGINT_USE_FFT
    static vector<int> _fft_mult_(const vector<int> &a, const vector<int> &b) {
        vector<int> ta(a.size() * 2), tb(b.size() * 2);
        static_assert(basen % 2 == 0, "basen has to be even");
        const static int M = pow(10, basen / 2);
        for (int i = 0; i < a.size(); ++i) {
            ta[i * 2] = a[i] % M;
            ta[i * 2 + 1] = a[i] / M;
        }
        for (int i = 0; i < b.size(); ++i) {
            tb[i * 2] = b[i] % M;
            tb[i * 2 + 1] = b[i] / M;
        }
        auto tc = fft::multiply(ta, tb);
        tc.resize(tc.size() / 2 * 2 + 10, 0);
        for (int i = 0; i + 1 < tc.size(); ++i) {
            tc[i + 1] += tc[i] / M;
            tc[i] %= M;
        }
        vector<int> res(tc.size() / 2);
        for (int i = 0; i < res.size(); ++i)
            res[i] = tc[i * 2] + tc[i * 2 + 1] * M;
        while (!res.empty() && res.back() == 0)
            res.pop_back();
        return res;
    }
    #endif

    static pair<vector<T>, vector<T>> _div_(vector<T> a, vector<T> b) {
        if (a.size() < b.size()) {
            return {{}, a};
        }
        vector<T> res;
        vector<T> c, c2;
        for (int i = (int)a.size() - b.size(); i >= 0; --i) {
            c.resize(b.size() + i);
            for (int j = 0; j < b.size(); ++j) {
                c[i + j] = b[j];
            }
            T L = 0, R = base;
            while (R - L > 1) {
                T C = (L + R) / 2;
                c2 = _mult_(c, {C});
                if (_comp_(a, c2)) {
                    R = C;
                } else {
                    L = C;
                }
            }
            c = _mult_(c, {L});
            _sub_(a, c);
            res.push_back(L);
        }
        reverse(res.begin(), res.end());
        return {res, a};
    }
};

string to_string(const Big &b) {
    if (b.v.empty()) return "0";
    string res;
    for (int i = (int)b.v.size() - 1; i >= 0; --i) {
        string t = to_string(b.v[i]);
        if (!res.empty())
            t = string(basen - t.size(), '0') + t;
        res += t;
    }
    if (b.minus)
        res.insert(res.begin(), '-');
    return res;
}

ostream &operator << (ostream &o, const Big &b) {
    return o << to_string(b);
};

istream &operator >> (istream &i, Big &b) {
    string s;
    i >> s;
    b = Big(s);
    return i;
}

Big gcd(Big a, Big b) {
    while (b != 0) {
        a %= b;
        swap(a, b);
    }
    return a;
}

const int P = 10;
const array<uint32_t, P> primes = {1038315533, 1070784149, 1152186131, 1226633593, 1383110039, 1811889307, 1863415583, 1871039267, 1893815057, 1925743987};

struct hash_my {
    size_t operator()(int x) const {
        x = ((x >> 16) ^ x) * 0x119de1f3;
        x = ((x >> 16) ^ x) * 0x119de1f3;
        x = (x >> 16) ^ x;
        return x;
    }

    size_t operator()(long long x) const {
        x = (x ^ (x >> 30)) * (0xbf58476d1ce4e5b9ll);
        x = (x ^ (x >> 27)) * (0x94d049bb133111ebll);
        x = x ^ (x >> 31);
        return x;
    }

    template<typename T, typename U>
    size_t operator()(const pair<T, U> &p) const {
        long long h1 = (*this)(p.first);
        long long h2 = (*this)(p.second);
        return (*this)(h1 ^ (h2 << 32) ^ (h2 >> 32));
    }
};

auto start_time = clock();

int main() {
    ios_base::sync_with_stdio(false); cin.tie(NULL);

    pow10[0] = 1;
    for (int i = 1; i < pow10.size(); ++i)
        pow10[i] = pow10[i - 1] * 10;

    // int t;
    // cin >> t;
    // while (t--) {
    //     Big a;
    //     int k;
    //     cin >> a >> k;
    //     Big b;
    //     cin >> b;
    //     a.modk(k);
    //     if (a != b) {
    //         cout << a << endl;
    //         cout << b << endl;
    //         show(a.v);
    //         show(b.v);
    //         assert(false);
    //     }
    //     cerr << "ok" << endl;
    // }

    map<array<uint32_t, P>, int> cnts;

    int n, k;
    cin >> n >> k;
    vector<Big> v;
    for (int i = 0; i < n; ++i) {
        string s;
        cin >> s;
        Big x(s);
        x.modk(k);
        v.pb(std::move(x));
    }

    show(v);

    Big b;
    Big mk(string(k, '9'));
    show(mk);
    Big b2;

    using namespace __gnu_pbds;
    vector<gp_hash_table<ll, int>> to;
    vector<int> res;
    to.eb();
    res.pb(0);

    // auto add_vec = [&](const vector<ll>& v) {
    //     int cur = 0;
    //     for (auto x : v) {
    //         auto it = to[cur].find(x);
    //         if (it != to[cur].end()) {
    //             cur = it->second;
    //         } else {
    //             int ccur = to.size();
    //             to.eb();
    //             res.pb(0);
    //             to[cur][x] = ccur;
    //             cur = ccur;
    //         }
    //     }
    //     res[cur]++;
    // };

    // auto ask_vec = [&](const vector<ll>& v) {
    //     int cur = 0;
    //     for (auto x : v) {
    //         auto it = to[cur].find(x);
    //         if (it != to[cur].end()) {
    //             cur = it->second;
    //         } else {
    //             return 0;
    //         }
    //     }
    //     return res[cur];
    // };

    vector<bool> is0;
    for (const auto& x : v) {
        is0.pb(count(x.v.begin(), x.v.end(), 0) == x.v.size());
    }
    int ans = 0;
    for (int i = 0; i < n; ++i) {
        if (!is0[i]) continue;
        for (int j = 0; j <= i; ++j) {
            if (!is0[j]) continue;
            for (int k = 0; k <= j; ++k) {
                ans += is0[k];
            }
        }
    }

    cerr << (double)(clock() - start_time) / CLOCKS_PER_SEC << endl;

    vector<array<uint32_t, P>> rems(n);
    for (int i = 0; i < n; ++i) {
        for (int pi = 0; pi < P; ++pi) {
            rems[i][pi] = v[i].modint(primes[pi]);
        }
    }

    array<uint32_t, P> remk;
    for (int pi = 0; pi < P; ++pi) {
        remk[pi] = mk.modint(primes[pi]);
    }

    for (int i = 0; i < n; ++i) {
        cnts[rems[i]]++;
        // add_vec(v[i].v);
        for (int j = i; j < n; ++j) {
            // b.v.assign(v[i].v.begin(), v[i].v.end());
            // b.minus = false;
            // b += v[j];
            // b.modk(k);
            // b2.v.assign(mk.v.begin(), mk.v.end());
            // b2.minus = false;
            // b2 -= b;
            // b2.modk(k);
            // b2.norm();

            array<uint32_t, P> rem = remk;
            for (int t = 0; t < P; ++t) {
                if (rem[t] < rems[i][t]) rem[t] += primes[t];
                rem[t] -= rems[i][t];
                if (rem[t] < rems[j][t]) rem[t] += primes[t];
                rem[t] -= rems[j][t];
            }
            {
                auto it = cnts.find(rem);
                if (it != cnts.end())
                    ans += it->second;
            }
            show(rems[i], rems[j], rem);
            for (int t = 0; t < P; ++t) {
                rem[t] += remk[t];
                if (rem[t] >= primes[t]) rem[t] -= primes[t];
            }
            show(rems[i], rems[j], rem);
            {
                auto it = cnts.find(rem);
                if (it != cnts.end())
                    ans += it->second;
            }
            // ans += ask_vec(b2.v);
            // {
            //     array<int, 10> rems;
            //     for (int pi = 0; pi < 10; ++pi) {
            //         rems[pi] = b2.modint(primes[pi]);
            //     }
            //     auto it = cnts.find(rems);
            //     if (it != cnts.end())
            //         ans += it->second;
            // }
        }
    }

    cout << ans << '\n';

    cerr << (double)(clock() - start_time) / CLOCKS_PER_SEC << endl;

    return 0;
}