QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#658891 | #9479. And DNA | ucup-team4435# | AC ✓ | 0ms | 3816kb | C++23 | 14.4kb | 2024-10-19 17:51:21 | 2024-10-19 17:51:22 |
Judging History
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