QOJ.ac

QOJ

ID题目提交者结果用时内存语言文件大小提交时间测评时间
#559605#6187. Digit Sum Problemucup-team4435AC ✓2527ms30276kbC++207.9kb2024-09-12 03:16:282024-09-12 03:16:29

Judging History

你现在查看的是最新测评结果

  • [2024-09-12 03:16:29]
  • 评测
  • 测评结果:AC
  • 用时:2527ms
  • 内存:30276kb
  • [2024-09-12 03:16:28]
  • 提交

answer

#include <bits/stdc++.h>
using namespace std;

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

#define all(a) begin(a), end(a)
#define len(a) int((a).size())

/*
 ! WARNING: MOD must be prime.
 ! WARNING: MOD must be less than 2^30.
 * Use .get() to get the stored value.
 */
template<uint32_t mod>
class montgomery {
    static_assert(mod < uint32_t(1) << 30, "mod < 2^30");
    using mint = montgomery<mod>;

private:
    uint32_t value;

    static constexpr uint32_t inv_neg_mod = []() {
        uint32_t x = mod;
        for (int i = 0; i < 4; ++i) {
            x *= uint32_t(2) - mod * x;
        }
        return -x;
    }();
    static_assert(mod * inv_neg_mod == -1);

    static constexpr uint32_t neg_mod = (-uint64_t(mod)) % mod;

    static uint32_t reduce(const uint64_t &value) {
        return (value + uint64_t(uint32_t(value) * inv_neg_mod) * mod) >> 32;
    }

    inline static const mint ONE = mint(1);

public:
    montgomery() : value(0) {}
    montgomery(const mint &x) : value(x.value) {}

    template<typename T, typename U = std::enable_if_t<std::is_integral<T>::value>>
    montgomery(const T &x) : value(!x ? 0 : reduce(int64_t(x % int32_t(mod) + int32_t(mod)) * neg_mod)) {}

    static constexpr uint32_t get_mod() {
        return mod;
    }

    uint32_t get() const {
        auto real_value = reduce(value);
        return real_value < mod ? real_value : real_value - mod;
    }

    template<typename T>
    mint power(T degree) const {
        degree = (degree % int32_t(mod - 1) + int32_t(mod - 1)) % int32_t(mod - 1);
        mint prod = 1, a = *this;
        for (; degree > 0; degree >>= 1, a *= a)
            if (degree & 1)
                prod *= a;

        return prod;
    }

    mint inv() const {
        return power(-1);
    }

    mint& operator=(const mint &x) {
        value = x.value;
        return *this;
    }

    mint& operator+=(const mint &x) {
        if (int32_t(value += x.value - (mod << 1)) < 0) {
            value += mod << 1;
        }
        return *this;
    }

    mint& operator-=(const mint &x) {
        if (int32_t(value -= x.value) < 0) {
            value += mod << 1;
        }
        return *this;
    }

    mint& operator*=(const mint &x) {
        value = reduce(uint64_t(value) * x.value);
        return *this;
    }

    mint& operator/=(const mint &x) {
        return *this *= x.inv();
    }

    friend mint operator+(const mint &x, const mint &y) {
        return mint(x) += y;
    }

    friend mint operator-(const mint &x, const mint &y) {
        return mint(x) -= y;
    }

    friend mint operator*(const mint &x, const mint &y) {
        return mint(x) *= y;
    }

    friend mint operator/(const mint &x, const mint &y) {
        return mint(x) /= y;
    }

    mint& operator++() {
        return *this += ONE;
    }

    mint& operator--() {
        return *this -= ONE;
    }

    mint operator++(int) {
        mint prev = *this;
        *this += ONE;
        return prev;
    }

    mint operator--(int) {
        mint prev = *this;
        *this -= ONE;
        return prev;
    }

    mint operator-() const {
        return mint(0) - *this;
    }

    bool operator==(const mint &x) const {
        return get() == x.get();
    }

    bool operator!=(const mint &x) const {
        return get() != x.get();
    }

    bool operator<(const mint &x) const {
        return get() < x.get();
    }

    template<typename T>
    explicit operator T() {
        return get();
    }

    friend std::istream& operator>>(std::istream &in, mint &x) {
        std::string s;
        in >> s;
        x = 0;
        bool neg = s[0] == '-';
        for (const auto c : s)
            if (c != '-')
                x = x * 10 + (c - '0');

        if (neg)
            x *= -1;

        return in;
    }

    friend std::ostream& operator<<(std::ostream &out, const mint &x) {
        return out << x.get();
    }

    static int32_t primitive_root() {
        if constexpr (mod == 1'000'000'007)
            return 5;
        if constexpr (mod == 998'244'353)
            return 3;
        if constexpr (mod == 786433)
            return 10;

        static int root = -1;
        if (root != -1)
            return root;

        std::vector<int> primes;
        int value = mod - 1;
        for (int i = 2; i * i <= value; i++)
            if (value % i == 0) {
                primes.push_back(i);
                while (value % i == 0)
                    value /= i;
            }

        if (value != 1)
            primes.push_back(value);

        for (int r = 2;; r++) {
            bool ok = true;
            for (auto p : primes)
                if ((mint(r).power((mod - 1) / p)).get() == 1) {
                    ok = false;
                    break;
                }

            if (ok)
                return root = r;
        }
    }
};

// constexpr uint32_t MOD = 1'000'000'007;
constexpr uint32_t MOD = 998'244'353;
using mint = montgomery<MOD>;

int main() {
    cin.tie(nullptr)->sync_with_stdio(false);

    ll n;
    mint a, b, c;
    cin >> n >> a >> b >> c;

    auto digit_sum = [&](ll x, int power) {
        int sum = 0;
        while (x > 0) {
            sum += x % power;
            x /= power;
        }
        return sum;
    };

    if (n <= 1000) {
        mint ans = 0;
        for (int k = 1; k <= n; k++) {
            ans += mint(a).power(k) * mint(b).power(digit_sum(k, 2)) * mint(c).power(digit_sum(k, 3));
        }
        cout << ans << '\n';
        return 0;
    }

    int sq = sqrt(n) / 2 + 1;

    int power2 = 1;
    while (power2 < sq) {
        power2 *= 2;
    }
    int power3 = 1;
    while (power3 < power2) {
        power3 *= 3;
    }

    vector<mint> val3(power3);
    for (int i = 0; i < power3; i++) {
        val3[i] = a.power(i) * c.power(digit_sum(i, 3));
    }
    // binary lifting stuf
    for (int power = 1; power < power2; power *= 2) {
        for (int i = 0; i + power < power3; i++) {
            val3[i] += val3[i + power] * b;
        }
    }

    vector<mint> val2(power2);
    for (int i = 0; i < power2; i++) {
        val2[i] = a.power(i) * b.power(digit_sum(i, 2));
    }
    // another shit binary lifting
    for (int power = 1; power < power3; power *= 3) {
        for (int i = 0; i < power2; i++) {
            if (i + power < power2) {
                val2[i] += val2[i + power] * c;
            }
            if (i + 2 * power < power2) {
                val2[i] += val2[i + 2 * power] * c * c;
            }
        }
    }

    mint a_power_prev2 = 1, a_power2 = a.power(power2);
    mint a_power_prev3 = 1, a_power3 = a.power(power3);

    ll left = 1, prev2 = 0, prev3 = 0;
    mint ans = 0;
    while (left <= n) {
        while (prev2 + power2 <= left) {
            prev2 += power2;
            a_power_prev2 *= a_power2;
        }
        while (prev3 + power3 <= left) {
            prev3 += power3;
            a_power_prev3 *= a_power3;
        }

        ll next2 = prev2 + power2 - 1;
        ll next3 = prev3 + power3 - 1;
        ll next = min({next2, next3, n});

        int ppc = digit_sum(prev2, 2);
        int sum = digit_sum(prev3, 3);

        if (next == next3 || (next == next2 && left == prev2)) {
            ans += a_power_prev3 * b.power(ppc) * c.power(sum) * val3[left - prev3];
        } else if (next == next2 && left == prev3) {
            ans += a_power_prev2 * b.power(ppc) * c.power(sum) * val2[left - prev2];
        } else {
            for (ll i = left; i <= next; i++) {
                ans += a.power(i) * b.power(ppc + digit_sum(i - prev2, 2))
                    * c.power(sum + digit_sum(i - prev3, 3));
            }
        }

        left = next + 1;
    }
    cout << ans << '\n';
}

详细

Test #1:

score: 100
Accepted
time: 1ms
memory: 3652kb

input:

123456 12345 234567 3456789

output:

664963464

result:

ok 1 number(s): "664963464"

Test #2:

score: 0
Accepted
time: 2527ms
memory: 30024kb

input:

9876543210987 12816 837595 128478

output:

7972694

result:

ok 1 number(s): "7972694"

Test #3:

score: 0
Accepted
time: 2146ms
memory: 30248kb

input:

9196665971964 727160879 966835565 746444639

output:

949890012

result:

ok 1 number(s): "949890012"

Test #4:

score: 0
Accepted
time: 2237ms
memory: 30080kb

input:

9361549073598 749653880 965489817 371100607

output:

949904373

result:

ok 1 number(s): "949904373"

Test #5:

score: 0
Accepted
time: 2163ms
memory: 29952kb

input:

9567572694963 193332930 544713669 390021151

output:

878781872

result:

ok 1 number(s): "878781872"

Test #6:

score: 0
Accepted
time: 2364ms
memory: 30020kb

input:

9769301349033 215825931 425927410 408941695

output:

351574791

result:

ok 1 number(s): "351574791"

Test #7:

score: 0
Accepted
time: 2366ms
memory: 30024kb

input:

9975324970399 657749333 5151262 729852127

output:

400022780

result:

ok 1 number(s): "400022780"

Test #8:

score: 0
Accepted
time: 0ms
memory: 3660kb

input:

1 149762920 266126484 107367523

output:

910371791

result:

ok 1 number(s): "910371791"

Test #9:

score: 0
Accepted
time: 506ms
memory: 7420kb

input:

903900971479 969144397 356713678 36786741

output:

414279957

result:

ok 1 number(s): "414279957"

Test #10:

score: 0
Accepted
time: 879ms
memory: 13648kb

input:

1940757501452 72683414 106545701 263512239

output:

786323834

result:

ok 1 number(s): "786323834"

Test #11:

score: 0
Accepted
time: 999ms
memory: 13596kb

input:

2914414844884 174466783 133201789 792227626

output:

187534312

result:

ok 1 number(s): "187534312"

Test #12:

score: 0
Accepted
time: 1122ms
memory: 13484kb

input:

3851250038782 553074217 881278164 297532837

output:

847958862

result:

ok 1 number(s): "847958862"

Test #13:

score: 0
Accepted
time: 1675ms
memory: 30276kb

input:

4692374803740 352867698 211679787 826248223

output:

426334178

result:

ok 1 number(s): "426334178"

Test #14:

score: 0
Accepted
time: 1853ms
memory: 30264kb

input:

5566041306806 454651067 959756163 633543322

output:

842296050

result:

ok 1 number(s): "842296050"

Test #15:

score: 0
Accepted
time: 2035ms
memory: 30028kb

input:

6902869060611 556434437 709588186 860268821

output:

897681255

result:

ok 1 number(s): "897681255"

Test #16:

score: 0
Accepted
time: 2179ms
memory: 30208kb

input:

7239695301792 356227918 736244273 667563920

output:

726280051

result:

ok 1 number(s): "726280051"

Test #17:

score: 0
Accepted
time: 2215ms
memory: 30008kb

input:

8217660029470 458011287 486076297 198034954

output:

967159922

result:

ok 1 number(s): "967159922"