# Project Euler 767
# Window into a Matrix II: B(10^5, 10^16) mod 1e9+7.
# Uses 3-prime NTT convolution with CRT reconstruction.
extern {
function calloc(n: i64, size: i64) -> ptr<void>
function free(p: ptr<void>) -> void
function malloc(n: i64) -> ptr<void>
function memcpy(dst: ptr<void>, src: ptr<void>, n: i64) -> ptr<void>
}
const MOD: i64 = 1000000007
const P1: i64 = 998244353
const P2: i64 = 1004535809
const P3: i64 = 469762049
let mut g_n: i64 = 0
let mut g_rev: ptr<i32> = null
let mut g_roots0: ptr<i64> = null
let mut g_roots1: ptr<i64> = null
let mut g_roots2: ptr<i64> = null
let mut g_roots_inv0: ptr<i64> = null
let mut g_roots_inv1: ptr<i64> = null
let mut g_roots_inv2: ptr<i64> = null
let mut g_inv_p1_mod_p2: i64 = 0
let mut g_p1_mod_p3: i64 = 0
let mut g_p12_mod_p3: i64 = 0
let mut g_inv_p12_mod_p3: i64 = 0
let mut g_p1_mod_mod: i64 = 0
let mut g_p12_mod_mod: i64 = 0
function mod_pow(a0: i64, e0: i64, mod: i64) -> i64 {
let mut r: i64 = 1 % mod
let mut a: i64 = a0 % mod
if a < 0 { a = a + mod }
let mut e: i64 = e0
while e > 0 {
if (e & 1) != 0 {
r = ((r as i128) * (a as i128) % (mod as i128)) as i64
}
a = ((a as i128) * (a as i128) % (mod as i128)) as i64
e = e >> 1
}
return r
}
function ceil_pow2(x: i64) -> i64 {
let mut n: i64 = 1
while n < x { n = n << 1 }
return n
}
function ntt(a: ptr<i64>, n: i64, mod: i64, roots: ptr<i64>, roots_inv: ptr<i64>, rev: ptr<i32>, invert: i32) -> void {
let mut i: i64 = 0
while i < n {
let j: i64 = rev[i] as i64
if i < j {
let t: i64 = a[i]
a[i] = a[j]
a[j] = t
}
i = i + 1
}
let r: ptr<i64> = if invert != 0 { roots_inv } else { roots }
let mut length: i64 = 2
while length <= n {
let half: i64 = length >> 1
let step: i64 = n / length
let mut i0: i64 = 0
while i0 < n {
let mut idx: i64 = 0
let mut j2: i64 = i0
while j2 < i0 + half {
let u: i64 = a[j2]
let v: i64 = ((a[j2 + half] as i128) * (r[idx] as i128) % (mod as i128)) as i64
let x: i64 = u + v
if x >= mod { x = x - mod }
let y: i64 = u - v
if y < 0 { y = y + mod }
a[j2] = x
a[j2 + half] = y
idx = idx + step
j2 = j2 + 1
}
i0 = i0 + length
}
length = length << 1
}
if invert != 0 {
let n_inv: i64 = mod_pow(n, mod - 2, mod)
let mut i3: i64 = 0
while i3 < n {
a[i3] = ((a[i3] as i128) * (n_inv as i128) % (mod as i128)) as i64
i3 = i3 + 1
}
}
}
function ctx_init(n: i64) -> void {
g_n = n
g_rev = malloc(n * 4) as ptr<i32>
let mut j: i32 = 0
let mut i: i64 = 1
while i < n {
let mut bit: i32 = (n >> 1) as i32
while (j & bit) != 0 {
j = j ^ bit
bit = bit >> 1
}
j = j ^ bit
g_rev[i] = j
i = i + 1
}
g_rev[0] = 0
let primes: array<i64, 3> = [P1, P2, P3]
let gs: array<i64, 3> = [3, 3, 3]
g_roots0 = malloc(n * 8) as ptr<i64>
g_roots_inv0 = malloc(n * 8) as ptr<i64>
g_roots1 = malloc(n * 8) as ptr<i64>
g_roots_inv1 = malloc(n * 8) as ptr<i64>
g_roots2 = malloc(n * 8) as ptr<i64>
g_roots_inv2 = malloc(n * 8) as ptr<i64>
let roots_arr: array<ptr<i64>, 3> = [g_roots0, g_roots1, g_roots2]
let roots_inv_arr: array<ptr<i64>, 3> = [g_roots_inv0, g_roots_inv1, g_roots_inv2]
let mut t: i32 = 0
while t < 3 {
let p: i64 = primes[t]
let g: i64 = gs[t]
let w: i64 = mod_pow(g, (p - 1) / n, p)
let w_inv: i64 = mod_pow(w, p - 2, p)
let roots: ptr<i64> = roots_arr[t]
let roots_inv: ptr<i64> = roots_inv_arr[t]
roots[0] = 1
roots_inv[0] = 1
let mut i2: i64 = 1
while i2 < n {
roots[i2] = ((roots[i2 - 1] as i128) * (w as i128) % (p as i128)) as i64
roots_inv[i2] = ((roots_inv[i2 - 1] as i128) * (w_inv as i128) % (p as i128)) as i64
i2 = i2 + 1
}
t = t + 1
}
g_inv_p1_mod_p2 = mod_pow(P1, P2 - 2, P2)
g_p1_mod_p3 = P1 % P3
g_p12_mod_p3 = ((P1 as i128) * (P2 as i128) % (P3 as i128)) as i64
g_inv_p12_mod_p3 = mod_pow(g_p12_mod_p3, P3 - 2, P3)
g_p1_mod_mod = P1 % MOD
g_p12_mod_mod = ((P1 as i128) * (P2 as i128) % (MOD as i128)) as i64
}
function ctx_free() -> void {
free(g_rev)
free(g_roots0)
free(g_roots_inv0)
free(g_roots1)
free(g_roots_inv1)
free(g_roots2)
free(g_roots_inv2)
}
function crt_reduce(out: ptr<i64>, c0: ptr<i64>, c1: ptr<i64>, c2: ptr<i64>, need: i64) -> void {
let mut i: i64 = 0
while i < need {
let r1: i64 = c0[i]
let r2: i64 = c1[i]
let r3: i64 = c2[i]
let t1: i64 = (((r2 - r1) % P2 + P2) % P2)
let t1m: i64 = ((t1 as i128) * (g_inv_p1_mod_p2 as i128) % (P2 as i128)) as i64
let x2_mod_p3: i64 = (r1 + ((g_p1_mod_p3 as i128) * (t1m as i128) % (P3 as i128)) as i64) % P3
let t2: i64 = (((r3 - x2_mod_p3) % P3 + P3) % P3)
let t2m: i64 = ((t2 as i128) * (g_inv_p12_mod_p3 as i128) % (P3 as i128)) as i64
let v: i64 = (r1 + ((g_p1_mod_mod as i128) * (t1m % MOD as i128) % (MOD as i128)) as i64
+ ((g_p12_mod_mod as i128) * (t2m % MOD as i128) % (MOD as i128)) as i64) % MOD
out[i] = v
i = i + 1
}
}
function convolution_mod(a: ptr<i64>, la: i64, b: ptr<i64>, lb: i64) -> ptr<i64> {
let need: i64 = la + lb - 1
let n: i64 = g_n
let primes: array<i64, 3> = [P1, P2, P3]
let roots_arr: array<ptr<i64>, 3> = [g_roots0, g_roots1, g_roots2]
let roots_inv_arr: array<ptr<i64>, 3> = [g_roots_inv0, g_roots_inv1, g_roots_inv2]
let c0: ptr<i64> = malloc(need * 8) as ptr<i64>
let c1: ptr<i64> = malloc(need * 8) as ptr<i64>
let c2: ptr<i64> = malloc(need * 8) as ptr<i64>
let convs: array<ptr<i64>, 3> = [c0, c1, c2]
let mut t: i32 = 0
while t < 3 {
let p: i64 = primes[t]
let fa: ptr<i64> = calloc(n, 8) as ptr<i64>
let fb: ptr<i64> = calloc(n, 8) as ptr<i64>
let mut i: i64 = 0
while i < la {
fa[i] = ((a[i] % p) + p) % p
i = i + 1
}
i = 0
while i < lb {
fb[i] = ((b[i] % p) + p) % p
i = i + 1
}
ntt(fa, n, p, roots_arr[t], roots_inv_arr[t], g_rev, 0)
ntt(fb, n, p, roots_arr[t], roots_inv_arr[t], g_rev, 0)
i = 0
while i < n {
fa[i] = ((fa[i] as i128) * (fb[i] as i128) % (p as i128)) as i64
i = i + 1
}
ntt(fa, n, p, roots_arr[t], roots_inv_arr[t], g_rev, 1)
memcpy(convs[t], fa, need * 8)
free(fa)
free(fb)
t = t + 1
}
let out: ptr<i64> = malloc(need * 8) as ptr<i64>
crt_reduce(out, c0, c1, c2, need)
free(c0)
free(c1)
free(c2)
return out
}
function convolution_square_mod(a: ptr<i64>, la: i64) -> ptr<i64> {
let need: i64 = 2 * la - 1
let n: i64 = g_n
let primes: array<i64, 3> = [P1, P2, P3]
let roots_arr: array<ptr<i64>, 3> = [g_roots0, g_roots1, g_roots2]
let roots_inv_arr: array<ptr<i64>, 3> = [g_roots_inv0, g_roots_inv1, g_roots_inv2]
let c0: ptr<i64> = malloc(need * 8) as ptr<i64>
let c1: ptr<i64> = malloc(need * 8) as ptr<i64>
let c2: ptr<i64> = malloc(need * 8) as ptr<i64>
let convs: array<ptr<i64>, 3> = [c0, c1, c2]
let mut t: i32 = 0
while t < 3 {
let p: i64 = primes[t]
let fa: ptr<i64> = calloc(n, 8) as ptr<i64>
let mut i: i64 = 0
while i < la {
fa[i] = ((a[i] % p) + p) % p
i = i + 1
}
ntt(fa, n, p, roots_arr[t], roots_inv_arr[t], g_rev, 0)
i = 0
while i < n {
fa[i] = ((fa[i] as i128) * (fa[i] as i128) % (p as i128)) as i64
i = i + 1
}
ntt(fa, n, p, roots_arr[t], roots_inv_arr[t], g_rev, 1)
memcpy(convs[t], fa, need * 8)
free(fa)
t = t + 1
}
let out: ptr<i64> = malloc(need * 8) as ptr<i64>
crt_reduce(out, c0, c1, c2, need)
free(c0)
free(c1)
free(c2)
return out
}
function pow16_mod(x: i64) -> i64 {
let x2: i64 = ((x as i128) * (x as i128) % (MOD as i128)) as i64
let x4: i64 = ((x2 as i128) * (x2 as i128) % (MOD as i128)) as i64
let x8: i64 = ((x4 as i128) * (x4 as i128) % (MOD as i128)) as i64
return ((x8 as i128) * (x8 as i128) % (MOD as i128)) as i64
}
function main() -> i32 {
let k: i64 = 100000
let n: i64 = 10000000000000000
let m: i64 = n / k
let A: i64 = mod_pow(2, m % (MOD - 1), MOD)
let fact: ptr<i64> = malloc((k + 1) * 8) as ptr<i64>
let inv_fact: ptr<i64> = malloc((k + 1) * 8) as ptr<i64>
fact[0] = 1
let mut i: i64 = 1
while i <= k {
fact[i] = ((fact[i - 1] as i128) * (i as i128) % (MOD as i128)) as i64
i = i + 1
}
inv_fact[k] = mod_pow(fact[k], MOD - 2, MOD)
i = k
while i >= 1 {
inv_fact[i - 1] = ((inv_fact[i] as i128) * (i as i128) % (MOD as i128)) as i64
i = i - 1
}
let fact16: ptr<i64> = malloc((k + 1) * 8) as ptr<i64>
let inv_fact16: ptr<i64> = malloc((k + 1) * 8) as ptr<i64>
i = 0
while i <= k {
fact16[i] = pow16_mod(fact[i])
inv_fact16[i] = pow16_mod(inv_fact[i])
i = i + 1
}
let need: i64 = 2 * (k + 1) - 1
let ntt_len: i64 = ceil_pow2(need)
ctx_init(ntt_len)
let conv_aa: ptr<i64> = convolution_square_mod(inv_fact16, k + 1)
let f: ptr<i64> = malloc((k + 1) * 8) as ptr<i64>
i = 0
while i <= k {
f[i] = ((fact16[i] as i128) * (conv_aa[i] as i128) % (MOD as i128)) as i64
i = i + 1
}
free(conv_aa)
let fprime: ptr<i64> = malloc((k + 1) * 8) as ptr<i64>
i = 0
while i <= k {
fprime[i] = ((f[i] as i128) * (inv_fact[i] as i128) % (MOD as i128)) as i64
i = i + 1
}
let neg2: i64 = MOD - 2
let b: ptr<i64> = malloc((k + 1) * 8) as ptr<i64>
let mut p: i64 = 1
i = 0
while i <= k {
b[i] = ((p as i128) * (inv_fact[i] as i128) % (MOD as i128)) as i64
p = ((p as i128) * (neg2 as i128) % (MOD as i128)) as i64
i = i + 1
}
let conv_fb: ptr<i64> = convolution_mod(fprime, k + 1, b, k + 1)
let S: ptr<i64> = malloc((k + 1) * 8) as ptr<i64>
i = 0
while i <= k {
S[i] = ((conv_fb[i] as i128) * (fact[i] as i128) % (MOD as i128)) as i64
i = i + 1
}
free(conv_fb)
let powA: ptr<i64> = malloc((k + 1) * 8) as ptr<i64>
powA[0] = 1
i = 1
while i <= k {
powA[i] = ((powA[i - 1] as i128) * (A as i128) % (MOD as i128)) as i64
i = i + 1
}
let fk: i64 = fact[k]
let mut ans: i64 = 0
i = 0
while i <= k {
let comb: i64 = ((fk as i128) * (inv_fact[i] as i128) % (MOD as i128)) as i64
let comb2: i64 = ((comb as i128) * (inv_fact[k - i] as i128) % (MOD as i128)) as i64
let term: i64 = ((comb2 as i128) * (powA[i] as i128) % (MOD as i128)) as i64
let term2: i64 = ((term as i128) * (S[k - i] as i128) % (MOD as i128)) as i64
ans = (ans + term2) % MOD
i = i + 1
}
free(fact)
free(inv_fact)
free(fact16)
free(inv_fact16)
free(f)
free(fprime)
free(b)
free(S)
free(powA)
ctx_free()
printf("%lld\n", ans)
return 0
}
Generated C
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Flow runtime helpers */
typedef struct flow_temp_node { struct flow_temp_node* next; } flow_temp_node;
static flow_temp_node* flow_temp_head = NULL;
static int flow_temp_atexit_set = 0;
__attribute__((unused)) static void flow_temp_free_all(void) {
while (flow_temp_head) {
flow_temp_node* n = flow_temp_head;
flow_temp_head = n->next;
free(n);
}
}
__attribute__((unused)) static void* flow_temp_alloc(size_t nbytes) {
flow_temp_node* node = (flow_temp_node*)malloc(sizeof(flow_temp_node) + nbytes);
if (!node) return NULL;
node->next = flow_temp_head;
flow_temp_head = node;
if (!flow_temp_atexit_set) {
flow_temp_atexit_set = 1;
atexit(flow_temp_free_all);
}
return (void*)(node + 1);
}
#ifndef FLOW_DIAG
#define FLOW_DIAG(msg) fprintf(stderr, "%s", (msg))
#endif
#ifndef FLOW_LOG
#define FLOW_LOG(fmt, ...) printf(fmt, __VA_ARGS__)
#endif
#ifndef FLOW_LOG_EMPTY
#define FLOW_LOG_EMPTY(fmt) printf(fmt)
#endif
static char* flow_strcat(const char* a, const char* b) {
size_t la = strlen(a ? a : ""), lb = strlen(b ? b : "");
char* r = (char*)flow_temp_alloc(la + lb + 1);
if (!r) return NULL;
if (la) memcpy(r, a, la);
if (lb) memcpy(r + la, b, lb);
r[la + lb] = '\0';
return r;
}
#define __flow_in_arr(arr, val) __extension__ ({ \
int _found = 0; \
size_t _n = sizeof(arr)/sizeof((arr)[0]); \
for (size_t _i = 0; _i < _n; _i++) { \
if ((arr)[_i] == (val)) { _found = 1; break; } \
} _found; })
/* Unified fault handler (MISRA #279) — override with -DFLOW_FAULT_HANDLER=fn */
#ifndef FLOW_FAULT_HANDLER
__attribute__((unused)) static inline void flow_fault_handler(const char* msg) {
fprintf(stderr, "flow: %s\n", msg ? msg : "fault");
abort();
#if defined(__GNUC__) || defined(__clang__)
__builtin_unreachable();
#endif
}
#else
#define flow_fault_handler FLOW_FAULT_HANDLER
#endif
#define flow_div_by_zero_handler() flow_fault_handler("division by zero")
#define flow_shift_ub_handler() flow_fault_handler("invalid shift (amount out of range or left-shift of negative)")
#ifndef FLOW_CHECKED_DIV
#define FLOW_CHECKED_DIV(L, R) (((R) != 0) ? ((L) / (R)) : (flow_div_by_zero_handler(), (L) * 0))
#endif
#ifndef FLOW_CHECKED_MOD
#define FLOW_CHECKED_MOD(L, R) (((R) != 0) ? ((L) % (R)) : (flow_div_by_zero_handler(), (L) * 0))
#endif
#ifndef FLOW_CHECKED_SHL
#define FLOW_CHECKED_SHL(L, R) ((((R) >= 0) && ((unsigned long long)(R) < (sizeof(L) * 8ull)) && ((L) >= 0)) ? ((L) << (R)) : (flow_shift_ub_handler(), (L) * 0))
#endif
#ifndef FLOW_CHECKED_SHR
#define FLOW_CHECKED_SHR(L, R) ((((R) >= 0) && ((unsigned long long)(R) < (sizeof(L) * 8ull))) ? ((L) >> (R)) : (flow_shift_ub_handler(), (L) * 0))
#endif
#include <math.h>
void* _ui_state = NULL;
static inline float i32_to_f32(int32_t v) { return (float)v; }
/* Host stub for @gpu kernels (device codegen replaces this). */
static inline int32_t gpu_thread_id(void) { return 0; }
int64_t mod_pow_i64_i64_i64(int64_t a0, int64_t e0, int64_t mod);
int64_t ceil_pow2_i64(int64_t x);
void ntt_ptr_i64_i64_i64_ptr_i64_ptr_i64_ptr_i32_i32(int64_t* a, int64_t n, int64_t mod, int64_t* roots, int64_t* roots_inv, int32_t* rev, int32_t invert);
void ctx_init_i64(int64_t n);
void ctx_free(void);
void crt_reduce_ptr_i64_ptr_i64_ptr_i64_ptr_i64_i64(int64_t* out, int64_t* c0, int64_t* c1, int64_t* c2, int64_t need);
int64_t* convolution_mod_ptr_i64_i64_ptr_i64_i64(int64_t* a, int64_t la, int64_t* b, int64_t lb);
int64_t* convolution_square_mod_ptr_i64_i64(int64_t* a, int64_t la);
int64_t pow16_mod_i64(int64_t x);
int32_t main(void);
static const int64_t MOD = 1000000007;
static const int64_t P1 = 998244353;
static const int64_t P2 = 1004535809;
static const int64_t P3 = 469762049;
/* Module statics */
static int64_t g_n = 0;
static int32_t* g_rev = NULL;
static int64_t* g_roots0 = NULL;
static int64_t* g_roots1 = NULL;
static int64_t* g_roots2 = NULL;
static int64_t* g_roots_inv0 = NULL;
static int64_t* g_roots_inv1 = NULL;
static int64_t* g_roots_inv2 = NULL;
static int64_t g_inv_p1_mod_p2 = 0;
static int64_t g_p1_mod_p3 = 0;
static int64_t g_p12_mod_p3 = 0;
static int64_t g_inv_p12_mod_p3 = 0;
static int64_t g_p1_mod_mod = 0;
static int64_t g_p12_mod_mod = 0;
int64_t mod_pow_i64_i64_i64(int64_t a0, int64_t e0, int64_t mod) {
int64_t r = FLOW_CHECKED_MOD((1), (mod));
int64_t a = FLOW_CHECKED_MOD((a0), (mod));
if (a < 0) {
a = (a + mod);
}
int64_t e = e0;
while (e > 0) {
if ((e & 1) != 0) {
r = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(r)) * ((__int128)(a)))), (((__int128)(mod))))));
}
a = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(a)) * ((__int128)(a)))), (((__int128)(mod))))));
e = FLOW_CHECKED_SHR((e), (1));
}
return r;
}
int64_t ceil_pow2_i64(int64_t x) {
int64_t n = 1;
while (n < x) {
n = FLOW_CHECKED_SHL((n), (1));
}
return n;
}
void ntt_ptr_i64_i64_i64_ptr_i64_ptr_i64_ptr_i32_i32(int64_t* a, int64_t n, int64_t mod, int64_t* roots, int64_t* roots_inv, int32_t* rev, int32_t invert) {
int64_t i = 0;
while (i < n) {
int64_t j = ((int64_t)(rev[i]));
if (i < j) {
int64_t t = a[i];
a[i] = a[j];
a[j] = t;
}
i = (i + 1);
}
int64_t* r = (int64_t*)(((invert != 0) ? (roots_inv) : (roots)));
int64_t length = 2;
while (length <= n) {
int64_t half = FLOW_CHECKED_SHR((length), (1));
int64_t step = FLOW_CHECKED_DIV((n), (length));
int64_t i0 = 0;
while (i0 < n) {
int64_t idx = 0;
int64_t j2 = i0;
while (j2 < (i0 + half)) {
int64_t u = a[j2];
int64_t v = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(a[(j2 + half)])) * ((__int128)(r[idx])))), (((__int128)(mod))))));
int64_t x = (u + v);
if (x >= mod) {
x = (x - mod);
}
int64_t y = (u - v);
if (y < 0) {
y = (y + mod);
}
a[j2] = x;
a[(j2 + half)] = y;
idx = (idx + step);
j2 = (j2 + 1);
}
i0 = (i0 + length);
}
length = FLOW_CHECKED_SHL((length), (1));
}
if (invert != 0) {
int64_t n_inv = mod_pow_i64_i64_i64(n, (mod - 2), mod);
int64_t i3 = 0;
while (i3 < n) {
a[i3] = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(a[i3])) * ((__int128)(n_inv)))), (((__int128)(mod))))));
i3 = (i3 + 1);
}
}
}
void ctx_init_i64(int64_t n) {
g_n = n;
g_rev = ((int32_t*)(malloc((n * 4))));
int32_t j = 0;
int64_t i = 1;
while (i < n) {
int32_t bit = ((int32_t)(FLOW_CHECKED_SHR((n), (1))));
while ((j & bit) != 0) {
j = (j ^ bit);
bit = FLOW_CHECKED_SHR((bit), (1));
}
j = (j ^ bit);
g_rev[i] = j;
i = (i + 1);
}
g_rev[0] = 0;
int64_t primes[3] = { P1, P2, P3 };
int64_t gs[3] = { 3, 3, 3 };
g_roots0 = ((int64_t*)(malloc((n * 8))));
g_roots_inv0 = ((int64_t*)(malloc((n * 8))));
g_roots1 = ((int64_t*)(malloc((n * 8))));
g_roots_inv1 = ((int64_t*)(malloc((n * 8))));
g_roots2 = ((int64_t*)(malloc((n * 8))));
g_roots_inv2 = ((int64_t*)(malloc((n * 8))));
int64_t* roots_arr[3] = { g_roots0, g_roots1, g_roots2 };
int64_t* roots_inv_arr[3] = { g_roots_inv0, g_roots_inv1, g_roots_inv2 };
int32_t t = 0;
while (t < 3) {
int64_t p = (((unsigned)(t) < 3) ? primes[t] : (fprintf(stderr, "array index %d out of bounds (size %d)\n", (int)(t), 3), flow_fault_handler("array index out of bounds"), primes[0]));
int64_t g = (((unsigned)(t) < 3) ? gs[t] : (fprintf(stderr, "array index %d out of bounds (size %d)\n", (int)(t), 3), flow_fault_handler("array index out of bounds"), gs[0]));
int64_t w = mod_pow_i64_i64_i64(g, FLOW_CHECKED_DIV(((p - 1)), (n)), p);
int64_t w_inv = mod_pow_i64_i64_i64(w, (p - 2), p);
int64_t* roots = (int64_t*)((((unsigned)(t) < 3) ? roots_arr[t] : (fprintf(stderr, "array index %d out of bounds (size %d)\n", (int)(t), 3), flow_fault_handler("array index out of bounds"), roots_arr[0])));
int64_t* roots_inv = (int64_t*)((((unsigned)(t) < 3) ? roots_inv_arr[t] : (fprintf(stderr, "array index %d out of bounds (size %d)\n", (int)(t), 3), flow_fault_handler("array index out of bounds"), roots_inv_arr[0])));
roots[0] = 1;
roots_inv[0] = 1;
int64_t i2 = 1;
while (i2 < n) {
roots[i2] = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(roots[(i2 - 1)])) * ((__int128)(w)))), (((__int128)(p))))));
roots_inv[i2] = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(roots_inv[(i2 - 1)])) * ((__int128)(w_inv)))), (((__int128)(p))))));
i2 = (i2 + 1);
}
t = (t + 1);
}
g_inv_p1_mod_p2 = mod_pow_i64_i64_i64(P1, (P2 - 2), P2);
g_p1_mod_p3 = FLOW_CHECKED_MOD((P1), (P3));
g_p12_mod_p3 = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(P1)) * ((__int128)(P2)))), (((__int128)(P3))))));
g_inv_p12_mod_p3 = mod_pow_i64_i64_i64(g_p12_mod_p3, (P3 - 2), P3);
g_p1_mod_mod = FLOW_CHECKED_MOD((P1), (MOD));
g_p12_mod_mod = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(P1)) * ((__int128)(P2)))), (((__int128)(MOD))))));
}
void ctx_free(void) {
free(g_rev);
free(g_roots0);
free(g_roots_inv0);
free(g_roots1);
free(g_roots_inv1);
free(g_roots2);
free(g_roots_inv2);
}
void crt_reduce_ptr_i64_ptr_i64_ptr_i64_ptr_i64_i64(int64_t* out, int64_t* c0, int64_t* c1, int64_t* c2, int64_t need) {
int64_t i = 0;
while (i < need) {
int64_t r1 = c0[i];
int64_t r2 = c1[i];
int64_t r3 = c2[i];
int64_t t1 = FLOW_CHECKED_MOD(((FLOW_CHECKED_MOD(((r2 - r1)), (P2)) + P2)), (P2));
int64_t t1m = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(t1)) * ((__int128)(g_inv_p1_mod_p2)))), (((__int128)(P2))))));
int64_t x2_mod_p3 = FLOW_CHECKED_MOD(((r1 + ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(g_p1_mod_p3)) * ((__int128)(t1m)))), (((__int128)(P3)))))))), (P3));
int64_t t2 = FLOW_CHECKED_MOD(((FLOW_CHECKED_MOD(((r3 - x2_mod_p3)), (P3)) + P3)), (P3));
int64_t t2m = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(t2)) * ((__int128)(g_inv_p12_mod_p3)))), (((__int128)(P3))))));
int64_t v = FLOW_CHECKED_MOD((((r1 + ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(g_p1_mod_mod)) * FLOW_CHECKED_MOD((t1m), (((__int128)(MOD)))))), (((__int128)(MOD))))))) + ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(g_p12_mod_mod)) * FLOW_CHECKED_MOD((t2m), (((__int128)(MOD)))))), (((__int128)(MOD)))))))), (MOD));
out[i] = v;
i = (i + 1);
}
}
int64_t* convolution_mod_ptr_i64_i64_ptr_i64_i64(int64_t* a, int64_t la, int64_t* b, int64_t lb) {
int64_t need = ((la + lb) - 1);
int64_t n = g_n;
int64_t primes[3] = { P1, P2, P3 };
int64_t* roots_arr[3] = { g_roots0, g_roots1, g_roots2 };
int64_t* roots_inv_arr[3] = { g_roots_inv0, g_roots_inv1, g_roots_inv2 };
int64_t* c0 = (int64_t*)(((int64_t*)(malloc((need * 8)))));
int64_t* c1 = (int64_t*)(((int64_t*)(malloc((need * 8)))));
int64_t* c2 = (int64_t*)(((int64_t*)(malloc((need * 8)))));
int64_t* convs[3] = { c0, c1, c2 };
int32_t t = 0;
while (t < 3) {
int64_t p = (((unsigned)(t) < 3) ? primes[t] : (fprintf(stderr, "array index %d out of bounds (size %d)\n", (int)(t), 3), flow_fault_handler("array index out of bounds"), primes[0]));
int64_t* fa = (int64_t*)(((int64_t*)(calloc(n, 8))));
int64_t* fb = (int64_t*)(((int64_t*)(calloc(n, 8))));
int64_t i = 0;
while (i < la) {
fa[i] = FLOW_CHECKED_MOD(((FLOW_CHECKED_MOD((a[i]), (p)) + p)), (p));
i = (i + 1);
}
i = 0;
while (i < lb) {
fb[i] = FLOW_CHECKED_MOD(((FLOW_CHECKED_MOD((b[i]), (p)) + p)), (p));
i = (i + 1);
}
ntt_ptr_i64_i64_i64_ptr_i64_ptr_i64_ptr_i32_i32(fa, n, p, (((unsigned)(t) < 3) ? roots_arr[t] : (fprintf(stderr, "array index %d out of bounds (size %d)\n", (int)(t), 3), flow_fault_handler("array index out of bounds"), roots_arr[0])), (((unsigned)(t) < 3) ? roots_inv_arr[t] : (fprintf(stderr, "array index %d out of bounds (size %d)\n", (int)(t), 3), flow_fault_handler("array index out of bounds"), roots_inv_arr[0])), g_rev, 0);
ntt_ptr_i64_i64_i64_ptr_i64_ptr_i64_ptr_i32_i32(fb, n, p, (((unsigned)(t) < 3) ? roots_arr[t] : (fprintf(stderr, "array index %d out of bounds (size %d)\n", (int)(t), 3), flow_fault_handler("array index out of bounds"), roots_arr[0])), (((unsigned)(t) < 3) ? roots_inv_arr[t] : (fprintf(stderr, "array index %d out of bounds (size %d)\n", (int)(t), 3), flow_fault_handler("array index out of bounds"), roots_inv_arr[0])), g_rev, 0);
i = 0;
while (i < n) {
fa[i] = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(fa[i])) * ((__int128)(fb[i])))), (((__int128)(p))))));
i = (i + 1);
}
ntt_ptr_i64_i64_i64_ptr_i64_ptr_i64_ptr_i32_i32(fa, n, p, (((unsigned)(t) < 3) ? roots_arr[t] : (fprintf(stderr, "array index %d out of bounds (size %d)\n", (int)(t), 3), flow_fault_handler("array index out of bounds"), roots_arr[0])), (((unsigned)(t) < 3) ? roots_inv_arr[t] : (fprintf(stderr, "array index %d out of bounds (size %d)\n", (int)(t), 3), flow_fault_handler("array index out of bounds"), roots_inv_arr[0])), g_rev, 1);
memcpy((((unsigned)(t) < 3) ? convs[t] : (fprintf(stderr, "array index %d out of bounds (size %d)\n", (int)(t), 3), flow_fault_handler("array index out of bounds"), convs[0])), fa, (need * 8));
free(fa);
free(fb);
t = (t + 1);
}
int64_t* out = (int64_t*)(((int64_t*)(malloc((need * 8)))));
crt_reduce_ptr_i64_ptr_i64_ptr_i64_ptr_i64_i64(out, c0, c1, c2, need);
free(c0);
free(c1);
free(c2);
return out;
}
int64_t* convolution_square_mod_ptr_i64_i64(int64_t* a, int64_t la) {
int64_t need = ((2 * la) - 1);
int64_t n = g_n;
int64_t primes[3] = { P1, P2, P3 };
int64_t* roots_arr[3] = { g_roots0, g_roots1, g_roots2 };
int64_t* roots_inv_arr[3] = { g_roots_inv0, g_roots_inv1, g_roots_inv2 };
int64_t* c0 = (int64_t*)(((int64_t*)(malloc((need * 8)))));
int64_t* c1 = (int64_t*)(((int64_t*)(malloc((need * 8)))));
int64_t* c2 = (int64_t*)(((int64_t*)(malloc((need * 8)))));
int64_t* convs[3] = { c0, c1, c2 };
int32_t t = 0;
while (t < 3) {
int64_t p = (((unsigned)(t) < 3) ? primes[t] : (fprintf(stderr, "array index %d out of bounds (size %d)\n", (int)(t), 3), flow_fault_handler("array index out of bounds"), primes[0]));
int64_t* fa = (int64_t*)(((int64_t*)(calloc(n, 8))));
int64_t i = 0;
while (i < la) {
fa[i] = FLOW_CHECKED_MOD(((FLOW_CHECKED_MOD((a[i]), (p)) + p)), (p));
i = (i + 1);
}
ntt_ptr_i64_i64_i64_ptr_i64_ptr_i64_ptr_i32_i32(fa, n, p, (((unsigned)(t) < 3) ? roots_arr[t] : (fprintf(stderr, "array index %d out of bounds (size %d)\n", (int)(t), 3), flow_fault_handler("array index out of bounds"), roots_arr[0])), (((unsigned)(t) < 3) ? roots_inv_arr[t] : (fprintf(stderr, "array index %d out of bounds (size %d)\n", (int)(t), 3), flow_fault_handler("array index out of bounds"), roots_inv_arr[0])), g_rev, 0);
i = 0;
while (i < n) {
fa[i] = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(fa[i])) * ((__int128)(fa[i])))), (((__int128)(p))))));
i = (i + 1);
}
ntt_ptr_i64_i64_i64_ptr_i64_ptr_i64_ptr_i32_i32(fa, n, p, (((unsigned)(t) < 3) ? roots_arr[t] : (fprintf(stderr, "array index %d out of bounds (size %d)\n", (int)(t), 3), flow_fault_handler("array index out of bounds"), roots_arr[0])), (((unsigned)(t) < 3) ? roots_inv_arr[t] : (fprintf(stderr, "array index %d out of bounds (size %d)\n", (int)(t), 3), flow_fault_handler("array index out of bounds"), roots_inv_arr[0])), g_rev, 1);
memcpy((((unsigned)(t) < 3) ? convs[t] : (fprintf(stderr, "array index %d out of bounds (size %d)\n", (int)(t), 3), flow_fault_handler("array index out of bounds"), convs[0])), fa, (need * 8));
free(fa);
t = (t + 1);
}
int64_t* out = (int64_t*)(((int64_t*)(malloc((need * 8)))));
crt_reduce_ptr_i64_ptr_i64_ptr_i64_ptr_i64_i64(out, c0, c1, c2, need);
free(c0);
free(c1);
free(c2);
return out;
}
int64_t pow16_mod_i64(int64_t x) {
int64_t x2 = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(x)) * ((__int128)(x)))), (((__int128)(MOD))))));
int64_t x4 = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(x2)) * ((__int128)(x2)))), (((__int128)(MOD))))));
int64_t x8 = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(x4)) * ((__int128)(x4)))), (((__int128)(MOD))))));
return ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(x8)) * ((__int128)(x8)))), (((__int128)(MOD))))));
}
int32_t main(void) {
int64_t k = 100000;
int64_t n = 10000000000000000;
int64_t m = FLOW_CHECKED_DIV((n), (k));
int64_t A = mod_pow_i64_i64_i64(2, FLOW_CHECKED_MOD((m), ((MOD - 1))), MOD);
int64_t* fact = (int64_t*)(((int64_t*)(malloc(((k + 1) * 8)))));
int64_t* inv_fact = (int64_t*)(((int64_t*)(malloc(((k + 1) * 8)))));
fact[0] = 1;
int64_t i = 1;
while (i <= k) {
fact[i] = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(fact[(i - 1)])) * ((__int128)(i)))), (((__int128)(MOD))))));
i = (i + 1);
}
inv_fact[k] = mod_pow_i64_i64_i64(fact[k], (MOD - 2), MOD);
i = k;
while (i >= 1) {
inv_fact[(i - 1)] = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(inv_fact[i])) * ((__int128)(i)))), (((__int128)(MOD))))));
i = (i - 1);
}
int64_t* fact16 = (int64_t*)(((int64_t*)(malloc(((k + 1) * 8)))));
int64_t* inv_fact16 = (int64_t*)(((int64_t*)(malloc(((k + 1) * 8)))));
i = 0;
while (i <= k) {
fact16[i] = pow16_mod_i64(fact[i]);
inv_fact16[i] = pow16_mod_i64(inv_fact[i]);
i = (i + 1);
}
int64_t need = ((2 * (k + 1)) - 1);
int64_t ntt_len = ceil_pow2_i64(need);
ctx_init_i64(ntt_len);
int64_t* conv_aa = (int64_t*)(convolution_square_mod_ptr_i64_i64(inv_fact16, (k + 1)));
int64_t* f = (int64_t*)(((int64_t*)(malloc(((k + 1) * 8)))));
i = 0;
while (i <= k) {
f[i] = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(fact16[i])) * ((__int128)(conv_aa[i])))), (((__int128)(MOD))))));
i = (i + 1);
}
free(conv_aa);
int64_t* fprime = (int64_t*)(((int64_t*)(malloc(((k + 1) * 8)))));
i = 0;
while (i <= k) {
fprime[i] = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(f[i])) * ((__int128)(inv_fact[i])))), (((__int128)(MOD))))));
i = (i + 1);
}
int64_t neg2 = (MOD - 2);
int64_t* b = (int64_t*)(((int64_t*)(malloc(((k + 1) * 8)))));
int64_t p = 1;
i = 0;
while (i <= k) {
b[i] = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(p)) * ((__int128)(inv_fact[i])))), (((__int128)(MOD))))));
p = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(p)) * ((__int128)(neg2)))), (((__int128)(MOD))))));
i = (i + 1);
}
int64_t* conv_fb = (int64_t*)(convolution_mod_ptr_i64_i64_ptr_i64_i64(fprime, (k + 1), b, (k + 1)));
int64_t* S = (int64_t*)(((int64_t*)(malloc(((k + 1) * 8)))));
i = 0;
while (i <= k) {
S[i] = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(conv_fb[i])) * ((__int128)(fact[i])))), (((__int128)(MOD))))));
i = (i + 1);
}
free(conv_fb);
int64_t* powA = (int64_t*)(((int64_t*)(malloc(((k + 1) * 8)))));
powA[0] = 1;
i = 1;
while (i <= k) {
powA[i] = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(powA[(i - 1)])) * ((__int128)(A)))), (((__int128)(MOD))))));
i = (i + 1);
}
int64_t fk = fact[k];
int64_t ans = 0;
i = 0;
while (i <= k) {
int64_t comb = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(fk)) * ((__int128)(inv_fact[i])))), (((__int128)(MOD))))));
int64_t comb2 = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(comb)) * ((__int128)(inv_fact[(k - i)])))), (((__int128)(MOD))))));
int64_t term = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(comb2)) * ((__int128)(powA[i])))), (((__int128)(MOD))))));
int64_t term2 = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(term)) * ((__int128)(S[(k - i)])))), (((__int128)(MOD))))));
ans = FLOW_CHECKED_MOD(((ans + term2)), (MOD));
i = (i + 1);
}
free(fact);
free(inv_fact);
free(fact16);
free(inv_fact16);
free(f);
free(fprime);
free(b);
free(S);
free(powA);
ctx_free();
printf("%lld\n", ans);
return 0;
}