QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#658891#9479. And DNAucup-team4435#AC ✓0ms3816kbC++2314.4kb2024-10-19 17:51:212024-10-19 17:51:22

Judging History

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

  • [2024-10-19 17:51:22]
  • 评测
  • 测评结果:AC
  • 用时:0ms
  • 内存:3816kb
  • [2024-10-19 17:51:21]
  • 提交

answer

#pragma GCC optimize("Ofast")

#include "bits/stdc++.h"

#define rep(i, n) for (int i = 0; i < (n); ++i)
#define rep1(i, n) for (int i = 1; i < (n); ++i)
#define rep1n(i, n) for (int i = 1; i <= (n); ++i)
#define repr(i, n) for (int i = (n) - 1; i >= 0; --i)
#define pb push_back
#define eb emplace_back
#define all(a) (a).begin(), (a).end()
#define rall(a) (a).rbegin(), (a).rend()
#define each(x, a) for (auto &x : a)
#define ar array
#define vec vector
#define range(i, n) rep(i, n)

using namespace std;

using ll = long long;
using ull = unsigned long long;
using ld = long double;
using str = string;
using pi = pair<int, int>;
using pl = pair<ll, ll>;

using vi = vector<int>;
using vl = vector<ll>;
using vpi = vector<pair<int, int>>;
using vvi = vector<vi>;

int Bit(int mask, int b) { return (mask >> b) & 1; }

template<class T>
bool ckmin(T &a, const T &b) {
    if (b < a) {
        a = b;
        return true;
    }
    return false;
}

template<class T>
bool ckmax(T &a, const T &b) {
    if (b > a) {
        a = b;
        return true;
    }
    return false;
}

// [l, r)
template<typename T, typename F>
T FindFirstTrue(T l, T r, const F &predicat) {
    --l;
    while (r - l > 1) {
        T mid = l + (r - l) / 2;
        if (predicat(mid)) {
            r = mid;
        } else {
            l = mid;
        }
    }
    return r;
}


template<typename T, typename F>
T FindLastFalse(T l, T r, const F &predicat) {
    return FindFirstTrue(l, r, predicat) - 1;
}


const ll INF = 2e18;
const int INFi = 2e9;
const int N = 5e5 + 5;
const int LG = 20;

template<typename T>
int normalize(T value, int mod) {
    if (value < -mod || value >= 2 * mod) value %= mod;
    if (value < 0) value += mod;
    if (value >= mod) value -= mod;
    return value;
}

template<int mod>
struct static_modular_int {
    using mint = static_modular_int<mod>;

    int value;

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

    template<typename T, typename U = std::enable_if_t<std::is_integral<T>::value>>
    static_modular_int(T value) : value(normalize(value, mod)) {}

    template<typename T>
    mint power(T degree) const {
        degree = normalize(degree, 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) {
        value += x.value;
        if (value >= mod) value -= mod;
        return *this;
    }

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

    mint& operator*=(const mint &x) {
        value = int64_t(value) * x.value % mod;
        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++() {
        ++value;
        if (value == mod) value = 0;
        return *this;
    }

    mint& operator--() {
        --value;
        if (value == -1) value = mod - 1;
        return *this;
    }

    mint operator++(int) {
        mint prev = *this;
        value++;
        if (value == mod) value = 0;
        return prev;
    }

    mint operator--(int) {
        mint prev = *this;
        value--;
        if (value == -1) value = mod - 1;
        return prev;
    }

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

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

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

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

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

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

        return in;
    }

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

    static int 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)).value == 1) {
                    ok = false;
                    break;
                }
            }
            if (ok) return root = r;
        }
    }
};

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

namespace berlekamp_massey {
    template<typename T>
    std::vector<T> find_recurrence(const std::vector<T> &values) {
        if (values.empty())
            return {};

        std::vector<T> add_option{}, recurrence{};
        int add_position = -1;
        T add_value = values[1];
        for (int i = 0; i < int(values.size()); i++) {
            T value = 0;
            for (int j = 0; j < int(recurrence.size()); j++)
                value += values[i - j - 1] * recurrence[j];

            T delta = values[i] - value;
            if (delta == 0)
                continue;

            std::vector<T> new_recurrence;
            if (add_position == -1) {
                new_recurrence.assign(i + 1, 0);
            } else {
                new_recurrence = add_option;
                std::reverse(new_recurrence.begin(), new_recurrence.end());
                new_recurrence.push_back(-1);
                for (int it = 0; it < i - add_position - 1; it++)
                    new_recurrence.push_back(0);

                std::reverse(new_recurrence.begin(), new_recurrence.end());
                T coeff = -delta / add_value;
                for (auto &x : new_recurrence)
                    x *= coeff;

                if (new_recurrence.size() < recurrence.size())
                    new_recurrence.resize(recurrence.size());

                for (int i = 0; i < int(recurrence.size()); i++)
                    new_recurrence[i] += recurrence[i];
            }

            if (i - int(recurrence.size()) >= add_position - int(add_option.size()) || add_position == -1) {
                add_option = recurrence;
                add_position = i;
                add_value = delta;
            }
            recurrence = new_recurrence;
        }
        return recurrence;
    }

    template<typename T>
    std::vector<T> multiply(const std::vector<T> &first, const std::vector<T> &second) {
        // can be replaced with fft multiplication
        std::vector<T> prod(max(0, int(first.size() + second.size()) - 1));
        for (int i = 0; i < int(first.size()); i++)
            for (int j = 0; j < int(second.size()); j++)
                prod[i + j] += first[i] * second[j];

        return prod;
    }

    template<typename T>
    std::vector<T> find_remainder(std::vector<T> first, const std::vector<T> &second) {
        // can be replaced with fft division
        if (second.empty())
            return {};

        assert(second.back() != 0);
        while (!first.empty() && first.size() >= second.size()) {
            if (first.back() == 0) {
                first.pop_back();
                continue;
            }
            T coeff = first.back() / second.back();
            for (int i = 0; i < int(second.size()); i++)
                first[int(first.size()) - int(second.size()) + i] -= coeff * second[i];
        }
        return first;
    }

    template<typename T>
    std::vector<T> find_remainder(std::vector<T> recurrence, int64_t k) {
        while (!recurrence.empty() && recurrence.back() == 0)
            recurrence.pop_back();

        std::vector<T> result{1}, value{0, 1};
        for (; k; k >>= 1) {
            if (k & 1)
                result = find_remainder(multiply(result, value), recurrence);

            value = find_remainder(multiply(value, value), recurrence);
        }
        return result;
    }

    template<typename T>
    T find_kth(const std::vector<T> &values, std::vector<T> recurrence, int64_t k) {
        std::reverse(recurrence.begin(), recurrence.end());
        recurrence.push_back(-1);
        std::vector<T> poly = find_remainder(recurrence, k);
        T result = 0;
        for (int i = 0; i < int(poly.size()); i++)
            result += poly[i] * values[i];

        return result;
    }
} // berlekamp_massey

namespace combinatorics {
    std::vector<mint> fact_, ifact_, inv_;

    void reserve(int size) {
        fact_.reserve(size + 1);
        ifact_.reserve(size + 1);
        inv_.reserve(size + 1);
    }

    void resize(int size) {
        if (fact_.empty()) {
            fact_ = {mint(1), mint(1)};
            ifact_ = {mint(1), mint(1)};
            inv_ = {mint(0), mint(1)};
        }
        for (int pos = fact_.size(); pos <= size; pos++) {
            fact_.push_back(fact_.back() * mint(pos));
            inv_.push_back(-inv_[MOD % pos] * mint(MOD / pos));
            ifact_.push_back(ifact_.back() * inv_[pos]);
        }
    }

    struct combinatorics_info {
        std::vector<mint> &data;

        combinatorics_info(std::vector<mint> &data) : data(data) {}

        mint operator[](int pos) {
            if (pos >= int(data.size()))
                resize(pos);

            return data[pos];
        }
    } fact(fact_), ifact(ifact_), inv(inv_);

    mint choose(int n, int k) {
        if (n < k || k < 0 || n < 0)
            return mint(0);

        return fact[n] * ifact[k] * ifact[n - k];
    }
}

using combinatorics::fact;
using combinatorics::ifact;
using combinatorics::inv;
using combinatorics::choose;

namespace ext_combinatorics {
    // distribute n equal elements into k groups
    mint distribute(int n, int k) {
        return choose(n + k - 1, n);
    }

    // count number of seqs with n '(' and m ')' and bal always >= 0
    mint catalan_nm(int n, int m) {
        assert(n >= m);
        return choose(m + n, m) - choose(m + n, m - 1);
    }

    mint catalan(int n) {
        return catalan_nm(n, n);
    }

    // count number of bracket seqs, bal always >= 0
    mint catalan_bal(int n, int start_balance = 0, int end_balance = 0) {
        if ((n + start_balance + end_balance) % 2 != 0) return 0;
        if (start_balance < 0 || end_balance < 0) return 0;
        return choose(n, (n + end_balance - start_balance) / 2) - choose(n, (n - end_balance - start_balance - 2) / 2);
    }

    // from (0, 0) to (x, y)
    mint grid_path(int x, int y) {
        return choose(x + y, x);
    }

    // from (0, 0) to (x, y) not touch low y=x+b
    mint grid_path_low(int x, int y, int b) {
        if (b >= 0) return 0;
        return grid_path(x, y) - grid_path(y - b, x + b);
    }

    // from (0, 0) to (x, y) not touch up y=x+b
    // O((x + y) / |b2 - b1|)
    mint grid_path_up(int x, int y, int b) {
        if (b <= 0) return 0;
        return grid_path(x, y) - grid_path(y - b, x + b);
    }

    // from (0, 0) to (x, y) touch L -LU +LUL -LULU ....
    // O((x + y) / |b2 - b1|)
    mint grid_calc_LUL(int x, int y, int b1, int b2) {
        swap(x, y);
        x -= b1;
        y += b1;
        if (x < 0 || y < 0) return 0;
        return grid_path(x, y) - grid_calc_LUL(y, x, -b2, -b1);
    }

    // from (0, 0) to (x, y) not touch low y=x+b1, up y=x+b2
    // O((x + y) / |b2 - b1|)
    mint grid_path_2(int x, int y, int b1, int b2) {
        return grid_path(x, y) - grid_calc_LUL(x, y, b1, b2) - grid_calc_LUL(y, x, -b2, -b1);
    }

    // probability what we end in L+R after infinity random walk, if we start at L, and absorbing points is 0, L+R.
    mint gambler_ruin_right(int L, int R, mint p_right) {
        assert(L >= 1 && R >= 1);
        if (p_right * 2 == 1) return mint(L) / mint(L + R);
        if (p_right == 1) return 1;
        if (p_right == 0) return 0;
        mint v = (1 - p_right) / p_right;
        return (1 - v.power(L)) / (1 - v.power(L + R));
    }

    mint gambler_ruin_left(int L, int R, mint p_left) {
        return 1 - gambler_ruin_right(L, R, 1 - p_left);
    }
}

vector<mint> start;
vector<mint> rec;

void precalc() {
    for(int n = 3; n <= 10; ++n) {
        mint ans = 0;
        for(int k = 1; k * 2 <= n; ++k) {
            ans += choose(k, n - k * 2) * n / k;
        }
        start.push_back(ans);
//        cerr << ans << endl;
    }
    rec = berlekamp_massey::find_recurrence(start);
    cerr << rec.size() << endl;
}

void solve() {
    int n, m; cin >> n >> m;

    ar<mint, 2> dp = {1, 0};

    mint who = berlekamp_massey::find_kth(start, rec, n - 3);

    while (m != 0) {
        ar<mint, 2> dp2 = {0, 0};
        int c = (m & 1);
        rep(i, 2) {
            mint val = dp[i];
            int nd = c ^ i;

            if (nd == 0) {
                dp2[(2+i)/2] += val;
                dp2[i/2] += val;
            } else {
                dp2[(1+i)/2] += val * who;
            }
        }
        swap(dp, dp2);
        m /= 2;
    }
    cout << dp[0] << '\n';
}

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout << setprecision(12) << fixed;
    int t = 1;
    precalc();
//    cin >> t;
    rep(i, t) {
        solve();
    }
    return 0;
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 0ms
memory: 3564kb

input:

3 2

output:

4

result:

ok "4"

Test #2:

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

input:

3 0

output:

1

result:

ok "1"

Test #3:

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

input:

100 100

output:

343406454

result:

ok "343406454"

Test #4:

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

input:

686579306 119540831

output:

260602195

result:

ok "260602195"

Test #5:

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

input:

26855095 796233790

output:

492736984

result:

ok "492736984"

Test #6:

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

input:

295310488 262950628

output:

503008241

result:

ok "503008241"

Test #7:

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

input:

239670714 149827706

output:

994702969

result:

ok "994702969"

Test #8:

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

input:

790779949 110053353

output:

898252188

result:

ok "898252188"

Test #9:

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

input:

726600542 795285932

output:

183726777

result:

ok "183726777"

Test #10:

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

input:

957970519 585582861

output:

298814018

result:

ok "298814018"

Test #11:

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

input:

93349859 634036506

output:

110693443

result:

ok "110693443"

Test #12:

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

input:

453035113 34126396

output:

306244220

result:

ok "306244220"

Test #13:

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

input:

31994526 100604502

output:

930620701

result:

ok "930620701"

Test #14:

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

input:

234760741 249817734

output:

440195858

result:

ok "440195858"

Test #15:

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

input:

542621111 646412689

output:

207377992

result:

ok "207377992"

Test #16:

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

input:

28492783 602632297

output:

65234506

result:

ok "65234506"

Test #17:

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

input:

213500301 768820204

output:

540205113

result:

ok "540205113"

Test #18:

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

input:

697808101 753041955

output:

93561295

result:

ok "93561295"

Test #19:

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

input:

585126464 450455977

output:

91109717

result:

ok "91109717"

Test #20:

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

input:

236696315 482334538

output:

925575199

result:

ok "925575199"

Test #21:

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

input:

632719214 298704996

output:

358926097

result:

ok "358926097"

Test #22:

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

input:

869119333 933404114

output:

318501108

result:

ok "318501108"

Test #23:

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

input:

6977994 814763202

output:

585332987

result:

ok "585332987"

Test #24:

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

input:

3 1

output:

3

result:

ok "3"

Test #25:

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

input:

3 1000000000

output:

279679226

result:

ok "279679226"

Test #26:

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

input:

4 0

output:

1

result:

ok "1"

Test #27:

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

input:

4 1

output:

2

result:

ok "2"

Test #28:

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

input:

4 1000000000

output:

1755648

result:

ok "1755648"

Test #29:

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

input:

1000000000 0

output:

1

result:

ok "1"

Test #30:

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

input:

1000000000 1

output:

696798313

result:

ok "696798313"

Test #31:

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

input:

1000000000 1000000000

output:

703786301

result:

ok "703786301"

Extra Test:

score: 0
Extra Test Passed