QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#559605 | #6187. Digit Sum Problem | ucup-team4435 | AC ✓ | 2527ms | 30276kb | C++20 | 7.9kb | 2024-09-12 03:16:28 | 2024-09-12 03:16:29 |
Judging History
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';
}
Details
Tip: Click on the bar to expand more detailed information
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"