Problem 554

Centaurs on a Chess Board C(n) = 8*C(2n,n) - 3n^2 - 2n - 7; sum C(F_i) for i=2..90 mod 10^8+7 via Lucas.

Answer89539872
Output89539872
StatusPASS
Native helperno
Runtime1920 ms
Peak memory1184 KB
Time complexityO(n^2) (estimated)
Space complexityO(n^2) (estimated)

Performance comparison

MetricOur solutionBest known
Time complexityO(n^2)O(n log n)
Space complexityO(n^2)O(n)
ApproachFlow solutionModular DP or matrix exponentiation
VerdictSuboptimal

Flow source

# Project Euler 554
# Centaurs on a Chess Board
# C(n) = 8*C(2n,n) - 3n^2 - 2n - 7; sum C(F_i) for i=2..90 mod 10^8+7 via Lucas.

extern {
    function calloc(n: i64, size: i64) -> ptr<void>
    function free(p: ptr<void>) -> void
}

const MOD: i64 = 100000007
const NEED_CAP: i64 = 4096

let mut TARGETS: ptr<i64> = null
let mut FACT: ptr<i64> = null
let mut INVFACT: ptr<i64> = null
let mut NT: i64 = 0

function modpow(base0: i64, exp0: i64, mod: i64) -> i64 {
    let mut result: i64 = 1
    let mut base: i64 = base0 % mod
    let mut exp: i64 = exp0
    while exp > 0 {
        if (exp & 1) != 0 {
            result = ((result as i128) * (base as i128) % (mod as i128)) as i64
        }
        base = ((base as i128) * (base as i128) % (mod as i128)) as i64
        exp = exp >> 1
    }
    return result
}

function add_need(x: i64) -> void {
    if x < 0 || x >= MOD { return }
    let mut i: i64 = 0
    while i < NT {
        if TARGETS[i] == x { return }
        i = i + 1
    }
    TARGETS[NT] = x
    NT = NT + 1
}

function mark_binom_needs(n: i64) -> void {
    let mut N: i64 = 2 * n
    let mut K: i64 = n
    while N > 0 || K > 0 {
        let ni: i64 = N % MOD
        let ki: i64 = K % MOD
        if ki <= ni {
            add_need(ni)
            add_need(ki)
            add_need(ni - ki)
        }
        N = N / MOD
        K = K / MOD
    }
}

function sort_targets() -> void {
    let mut i: i64 = 1
    while i < NT {
        let key: i64 = TARGETS[i]
        let mut j: i64 = i - 1
        while j >= 0 && TARGETS[j] > key {
            TARGETS[j + 1] = TARGETS[j]
            j = j - 1
        }
        TARGETS[j + 1] = key
        i = i + 1
    }
}

function index_of(x: i64) -> i64 {
    let mut lo: i64 = 0
    let mut hi: i64 = NT - 1
    while lo <= hi {
        let mid: i64 = (lo + hi) / 2
        let v: i64 = TARGETS[mid]
        if v == x { return mid }
        if v < x { lo = mid + 1 } else { hi = mid - 1 }
    }
    return -1
}

function small_binom(n: i64, k: i64) -> i64 {
    if k < 0 || k > n { return 0 }
    let idx_n: i64 = index_of(n)
    let idx_k: i64 = index_of(k)
    let idx_nk: i64 = index_of(n - k)
    if idx_n < 0 || idx_k < 0 || idx_nk < 0 { return 0 }
    return ((FACT[idx_n] as i128) * (INVFACT[idx_k] as i128) % (MOD as i128) * (INVFACT[idx_nk] as i128) % (MOD as i128)) as i64
}

function lucas_binom(N0: i64, K0: i64) -> i64 {
    let mut N: i64 = N0
    let mut K: i64 = K0
    let mut res: i64 = 1
    while N > 0 || K > 0 {
        let ni: i64 = N % MOD
        let ki: i64 = K % MOD
        if ki > ni { return 0 }
        res = ((res as i128) * (small_binom(ni, ki) as i128) % (MOD as i128)) as i64
        N = N / MOD
        K = K / MOD
    }
    return res
}

function C_mod(n: i64) -> i64 {
    let b: i64 = lucas_binom(2 * n, n)
    let nn: i64 = n % MOD
    let poly: i64 = ((3 * nn % MOD) * nn + 2 * nn + 7) % MOD
    let mut r: i64 = (8 * b - poly) % MOD
    if r < 0 { r = r + MOD }
    return r
}

function main() -> i32 {
    let F: ptr<i64> = calloc(91, 8)
    if F == null { return 1 }
    F[0] = 0
    F[1] = 1
    let mut i: i64 = 2
    while i <= 90 {
        F[i] = F[i - 1] + F[i - 2]
        i = i + 1
    }

    TARGETS = calloc(NEED_CAP, 8)
    FACT = calloc(NEED_CAP, 8)
    INVFACT = calloc(NEED_CAP, 8)
    if TARGETS == null || FACT == null || INVFACT == null { return 1 }
    add_need(0)
    add_need(1)
    i = 2
    while i <= 90 {
        mark_binom_needs(F[i])
        i = i + 1
    }
    mark_binom_needs(1)
    mark_binom_needs(2)
    mark_binom_needs(10)
    sort_targets()

    let max_idx: i64 = TARGETS[NT - 1]
    let mut f: i64 = 1
    let mut ti: i64 = 0
    FACT[0] = 1
    INVFACT[0] = 1
    ti = 1
    i = 1
    while i <= max_idx {
        f = ((f as i128) * (i as i128) % (MOD as i128)) as i64
        if ti < NT && TARGETS[ti] == i {
            FACT[ti] = f
            INVFACT[ti] = modpow(f, MOD - 2, MOD)
            ti = ti + 1
        }
        i = i + 1
    }

    let mut ans: i64 = 0
    i = 2
    while i <= 90 {
        ans = ans + C_mod(F[i])
        if ans >= MOD { ans = ans - MOD }
        i = i + 1
    }
    printf("%lld\n", ans)

    free(F)
    free(TARGETS)
    free(FACT)
    free(INVFACT)
    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 modpow_i64_i64_i64(int64_t base0, int64_t exp0, int64_t mod);
void add_need_i64(int64_t x);
void mark_binom_needs_i64(int64_t n);
void sort_targets(void);
int64_t index_of_i64(int64_t x);
int64_t small_binom_i64_i64(int64_t n, int64_t k);
int64_t lucas_binom_i64_i64(int64_t N0, int64_t K0);
int64_t C_mod_i64(int64_t n);
int32_t main(void);

static const int64_t MOD = 100000007;
static const int64_t NEED_CAP = 4096;

/* Module statics */
static int64_t* TARGETS = NULL;
static int64_t* FACT = NULL;
static int64_t* INVFACT = NULL;
static int64_t NT = 0;



int64_t modpow_i64_i64_i64(int64_t base0, int64_t exp0, int64_t mod) {
    int64_t result = 1;
    int64_t base = FLOW_CHECKED_MOD((base0), (mod));
    int64_t exp = exp0;
    while (exp > 0) {
        if ((exp & 1) != 0) {
            result = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(result)) * ((__int128)(base)))), (((__int128)(mod))))));
        }
        base = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(base)) * ((__int128)(base)))), (((__int128)(mod))))));
        exp = FLOW_CHECKED_SHR((exp), (1));
    }
    return result;
}

void add_need_i64(int64_t x) {
    if ((x < 0 || x >= MOD)) {
        return;
    }
    int64_t i = 0;
    while (i < NT) {
        if (TARGETS[i] == x) {
            return;
        }
        i = (i + 1);
    }
    TARGETS[NT] = x;
    NT = (NT + 1);
}

void mark_binom_needs_i64(int64_t n) {
    int64_t N = (2 * n);
    int64_t K = n;
    while ((N > 0 || K > 0)) {
        int64_t ni = FLOW_CHECKED_MOD((N), (MOD));
        int64_t ki = FLOW_CHECKED_MOD((K), (MOD));
        if (ki <= ni) {
            add_need_i64(ni);
            add_need_i64(ki);
            add_need_i64((ni - ki));
        }
        N = FLOW_CHECKED_DIV((N), (MOD));
        K = FLOW_CHECKED_DIV((K), (MOD));
    }
}

void sort_targets(void) {
    int64_t i = 1;
    while (i < NT) {
        int64_t key = TARGETS[i];
        int64_t j = (i - 1);
        while ((j >= 0 && TARGETS[j] > key)) {
            TARGETS[(j + 1)] = TARGETS[j];
            j = (j - 1);
        }
        TARGETS[(j + 1)] = key;
        i = (i + 1);
    }
}

int64_t index_of_i64(int64_t x) {
    int64_t lo = 0;
    int64_t hi = (NT - 1);
    while (lo <= hi) {
        int64_t mid = FLOW_CHECKED_DIV(((lo + hi)), (2));
        int64_t v = TARGETS[mid];
        if (v == x) {
            return mid;
        }
        if (v < x) {
            lo = (mid + 1);
        } else {
            hi = (mid - 1);
        }
    }
    return (-1);
}

int64_t small_binom_i64_i64(int64_t n, int64_t k) {
    if ((k < 0 || k > n)) {
        return 0;
    }
    int64_t idx_n = index_of_i64(n);
    int64_t idx_k = index_of_i64(k);
    int64_t idx_nk = index_of_i64((n - k));
    if (((idx_n < 0 || idx_k < 0) || idx_nk < 0)) {
        return 0;
    }
    return ((int64_t)(FLOW_CHECKED_MOD(((FLOW_CHECKED_MOD(((((__int128)(FACT[idx_n])) * ((__int128)(INVFACT[idx_k])))), (((__int128)(MOD)))) * ((__int128)(INVFACT[idx_nk])))), (((__int128)(MOD))))));
}

int64_t lucas_binom_i64_i64(int64_t N0, int64_t K0) {
    int64_t N = N0;
    int64_t K = K0;
    int64_t res = 1;
    while ((N > 0 || K > 0)) {
        int64_t ni = FLOW_CHECKED_MOD((N), (MOD));
        int64_t ki = FLOW_CHECKED_MOD((K), (MOD));
        if (ki > ni) {
            return 0;
        }
        res = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(res)) * ((__int128)(small_binom_i64_i64(ni, ki))))), (((__int128)(MOD))))));
        N = FLOW_CHECKED_DIV((N), (MOD));
        K = FLOW_CHECKED_DIV((K), (MOD));
    }
    return res;
}

int64_t C_mod_i64(int64_t n) {
    int64_t b = lucas_binom_i64_i64((2 * n), n);
    int64_t nn = FLOW_CHECKED_MOD((n), (MOD));
    int64_t poly = FLOW_CHECKED_MOD(((((FLOW_CHECKED_MOD(((3 * nn)), (MOD)) * nn) + (2 * nn)) + 7)), (MOD));
    int64_t r = FLOW_CHECKED_MOD((((8 * b) - poly)), (MOD));
    if (r < 0) {
        r = (r + MOD);
    }
    return r;
}

int32_t main(void) {
    int64_t* F = (int64_t*)(calloc(91, 8));
    if (F == NULL) {
        return 1;
    }
    F[0] = 0;
    F[1] = 1;
    int64_t i = 2;
    while (i <= 90) {
        F[i] = (F[(i - 1)] + F[(i - 2)]);
        i = (i + 1);
    }
    TARGETS = calloc(NEED_CAP, 8);
    FACT = calloc(NEED_CAP, 8);
    INVFACT = calloc(NEED_CAP, 8);
    if (((TARGETS == NULL || FACT == NULL) || INVFACT == NULL)) {
        return 1;
    }
    add_need_i64(0);
    add_need_i64(1);
    i = 2;
    while (i <= 90) {
        mark_binom_needs_i64(F[i]);
        i = (i + 1);
    }
    mark_binom_needs_i64(1);
    mark_binom_needs_i64(2);
    mark_binom_needs_i64(10);
    sort_targets();
    int64_t max_idx = TARGETS[(NT - 1)];
    int64_t f = 1;
    int64_t ti = 0;
    FACT[0] = 1;
    INVFACT[0] = 1;
    ti = 1;
    i = 1;
    while (i <= max_idx) {
        f = ((int64_t)(FLOW_CHECKED_MOD(((((__int128)(f)) * ((__int128)(i)))), (((__int128)(MOD))))));
        if ((ti < NT && TARGETS[ti] == i)) {
            FACT[ti] = f;
            INVFACT[ti] = modpow_i64_i64_i64(f, (MOD - 2), MOD);
            ti = (ti + 1);
        }
        i = (i + 1);
    }
    int64_t ans = 0;
    i = 2;
    while (i <= 90) {
        ans = (ans + C_mod_i64(F[i]));
        if (ans >= MOD) {
            ans = (ans - MOD);
        }
        i = (i + 1);
    }
    printf("%lld\n", ans);
    free(F);
    free(TARGETS);
    free(FACT);
    free(INVFACT);
    return 0;
}

Generated MLIR

module {
  llvm.func @printf(!llvm.ptr, ...) -> i32
  llvm.mlir.global internal constant @str_0("%lld\n\00") {addr_space = 0 : i32} : !llvm.array<6 x i8>
  func.func private @calloc(i64, i64) -> !llvm.ptr
  func.func private @free(!llvm.ptr) -> ()
  // Constant: MOD
  llvm.mlir.global internal constant @MOD(100000007 : i64) : i64
  // Constant: NEED_CAP
  llvm.mlir.global internal constant @NEED_CAP(4096 : i64) : i64
  // Module static: TARGETS
  llvm.mlir.global internal @TARGETS() {addr_space = 0 : i32} : !llvm.ptr {
    %0 = llvm.mlir.zero : !llvm.ptr
    llvm.return %0 : !llvm.ptr
  }
  // Module static: FACT
  llvm.mlir.global internal @FACT() {addr_space = 0 : i32} : !llvm.ptr {
    %1 = llvm.mlir.zero : !llvm.ptr
    llvm.return %1 : !llvm.ptr
  }
  // Module static: INVFACT
  llvm.mlir.global internal @INVFACT() {addr_space = 0 : i32} : !llvm.ptr {
    %2 = llvm.mlir.zero : !llvm.ptr
    llvm.return %2 : !llvm.ptr
  }
  // Module static: NT
  llvm.mlir.global internal @NT(0 : i64) : i64
  func.func @modpow(%arg0: i64, %arg1: i64, %arg2: i64) -> i64 {
    %3 = arith.constant 1 : i32
    %4 = arith.extsi %3 : i32 to i64
    %5 = llvm.mlir.constant(1 : i64) : i64
    %6 = llvm.alloca %5 x i64 : (i64) -> !llvm.ptr
    llvm.store %4, %6 : i64, !llvm.ptr
    %7 = arith.remsi %arg0, %arg2 : i64
    %8 = llvm.mlir.constant(1 : i64) : i64
    %9 = llvm.alloca %8 x i64 : (i64) -> !llvm.ptr
    llvm.store %7, %9 : i64, !llvm.ptr
    %10 = llvm.mlir.constant(1 : i64) : i64
    %11 = llvm.alloca %10 x i64 : (i64) -> !llvm.ptr
    llvm.store %arg1, %11 : i64, !llvm.ptr
    cf.br ^bb0
    ^bb0:
    %12 = llvm.load %11 : !llvm.ptr -> i64
    %13 = arith.constant 0 : i32
    %15 = arith.extsi %13 : i32 to i64
    %14 = arith.cmpi sgt, %12, %15 : i64
    cf.cond_br %14, ^bb1, ^bb2
    ^bb1:
      %16 = llvm.load %11 : !llvm.ptr -> i64
      %17 = arith.constant 1 : i32
      %19 = arith.extsi %17 : i32 to i64
      %18 = arith.andi %16, %19 : i64
      %20 = arith.constant 0 : i32
      %22 = arith.extsi %20 : i32 to i64
      %21 = arith.cmpi ne, %18, %22 : i64
      cf.cond_br %21, ^bb3, ^bb4
      ^bb3:
        %23 = llvm.load %6 : !llvm.ptr -> i64
        %24 = arith.extsi %23 : i64 to i128
        %25 = llvm.load %9 : !llvm.ptr -> i64
        %26 = arith.extsi %25 : i64 to i128
        %28 = arith.trunci %24 : i128 to i64
        %29 = arith.trunci %26 : i128 to i64
        %27 = arith.muli %28, %29 : i64
        %30 = arith.extsi %arg2 : i64 to i128
        %32 = arith.trunci %30 : i128 to i64
        %31 = arith.remsi %27, %32 : i64
        llvm.store %31, %6 : i64, !llvm.ptr
        cf.br ^bb5
      ^bb4:
        cf.br ^bb5
      ^bb5:
      %33 = llvm.load %9 : !llvm.ptr -> i64
      %34 = arith.extsi %33 : i64 to i128
      %35 = llvm.load %9 : !llvm.ptr -> i64
      %36 = arith.extsi %35 : i64 to i128
      %38 = arith.trunci %34 : i128 to i64
      %39 = arith.trunci %36 : i128 to i64
      %37 = arith.muli %38, %39 : i64
      %40 = arith.extsi %arg2 : i64 to i128
      %42 = arith.trunci %40 : i128 to i64
      %41 = arith.remsi %37, %42 : i64
      llvm.store %41, %9 : i64, !llvm.ptr
      %43 = llvm.load %11 : !llvm.ptr -> i64
      %44 = arith.constant 1 : i32
      %46 = arith.extsi %44 : i32 to i64
      %45 = arith.shrsi %43, %46 : i64
      llvm.store %45, %11 : i64, !llvm.ptr
      cf.br ^bb0
    ^bb2:
    %47 = llvm.load %6 : !llvm.ptr -> i64
    func.return %47 : i64
  }
  func.func @add_need(%arg0: i64) -> () {
    %48 = arith.constant 0 : i32
    %50 = arith.extsi %48 : i32 to i64
    %49 = arith.cmpi slt, %arg0, %50 : i64
    %51 = scf.if %49 -> (i1) {
      %52 = arith.constant true
      scf.yield %52 : i1
    } else {
      %53 = llvm.mlir.addressof @MOD : !llvm.ptr
      %54 = llvm.load %53 : !llvm.ptr -> i64
      %55 = arith.cmpi sge, %arg0, %54 : i64
      scf.yield %55 : i1
    }
    cf.cond_br %51, ^bb6, ^bb7
    ^bb6:
      func.return
    ^bb7:
      cf.br ^bb8
    ^bb8:
    %56 = arith.constant 0 : i32
    %57 = arith.extsi %56 : i32 to i64
    %58 = llvm.mlir.constant(1 : i64) : i64
    %59 = llvm.alloca %58 x i64 : (i64) -> !llvm.ptr
    llvm.store %57, %59 : i64, !llvm.ptr
    cf.br ^bb9
    ^bb9:
    %60 = llvm.load %59 : !llvm.ptr -> i64
    %61 = llvm.mlir.addressof @NT : !llvm.ptr
    %62 = llvm.load %61 : !llvm.ptr -> i64
    %63 = arith.cmpi slt, %60, %62 : i64
    cf.cond_br %63, ^bb10, ^bb11
    ^bb10:
      %65 = llvm.mlir.addressof @TARGETS : !llvm.ptr
      %66 = llvm.load %65 : !llvm.ptr -> !llvm.ptr
      %67 = llvm.load %59 : !llvm.ptr -> i64
      %68 = llvm.getelementptr %66[%67] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %64 = llvm.load %68 : !llvm.ptr -> i64
      %69 = arith.cmpi eq, %64, %arg0 : i64
      cf.cond_br %69, ^bb12, ^bb13
      ^bb12:
        func.return
      ^bb13:
        cf.br ^bb14
      ^bb14:
      %70 = llvm.load %59 : !llvm.ptr -> i64
      %71 = arith.constant 1 : i32
      %73 = arith.extsi %71 : i32 to i64
      %72 = arith.addi %70, %73 : i64
      llvm.store %72, %59 : i64, !llvm.ptr
      cf.br ^bb9
    ^bb11:
    %74 = llvm.mlir.addressof @TARGETS : !llvm.ptr
    %75 = llvm.load %74 : !llvm.ptr -> !llvm.ptr
    %76 = llvm.mlir.addressof @NT : !llvm.ptr
    %77 = llvm.load %76 : !llvm.ptr -> i64
    %78 = llvm.getelementptr %75[%77] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %arg0, %78 : i64, !llvm.ptr
    %79 = llvm.mlir.addressof @NT : !llvm.ptr
    %80 = llvm.load %79 : !llvm.ptr -> i64
    %81 = arith.constant 1 : i32
    %83 = arith.extsi %81 : i32 to i64
    %82 = arith.addi %80, %83 : i64
    %84 = llvm.mlir.addressof @NT : !llvm.ptr
    llvm.store %82, %84 : i64, !llvm.ptr
    func.return
  }
  func.func @mark_binom_needs(%arg0: i64) -> () {
    %85 = arith.constant 2 : i32
    %87 = arith.extsi %85 : i32 to i64
    %86 = arith.muli %87, %arg0 : i64
    %88 = llvm.mlir.constant(1 : i64) : i64
    %89 = llvm.alloca %88 x i64 : (i64) -> !llvm.ptr
    llvm.store %86, %89 : i64, !llvm.ptr
    %90 = llvm.mlir.constant(1 : i64) : i64
    %91 = llvm.alloca %90 x i64 : (i64) -> !llvm.ptr
    llvm.store %arg0, %91 : i64, !llvm.ptr
    cf.br ^bb15
    ^bb15:
    %92 = llvm.load %89 : !llvm.ptr -> i64
    %93 = arith.constant 0 : i32
    %95 = arith.extsi %93 : i32 to i64
    %94 = arith.cmpi sgt, %92, %95 : i64
    %96 = scf.if %94 -> (i1) {
      %97 = arith.constant true
      scf.yield %97 : i1
    } else {
      %98 = llvm.load %91 : !llvm.ptr -> i64
      %99 = arith.constant 0 : i32
      %101 = arith.extsi %99 : i32 to i64
      %100 = arith.cmpi sgt, %98, %101 : i64
      scf.yield %100 : i1
    }
    cf.cond_br %96, ^bb16, ^bb17
    ^bb16:
      %102 = llvm.load %89 : !llvm.ptr -> i64
      %103 = llvm.mlir.addressof @MOD : !llvm.ptr
      %104 = llvm.load %103 : !llvm.ptr -> i64
      %105 = arith.remsi %102, %104 : i64
      %106 = llvm.load %91 : !llvm.ptr -> i64
      %107 = llvm.mlir.addressof @MOD : !llvm.ptr
      %108 = llvm.load %107 : !llvm.ptr -> i64
      %109 = arith.remsi %106, %108 : i64
      %110 = arith.cmpi sle, %109, %105 : i64
      cf.cond_br %110, ^bb18, ^bb19
      ^bb18:
        func.call @add_need(%105) : (i64) -> ()
        func.call @add_need(%109) : (i64) -> ()
        %114 = arith.subi %105, %109 : i64
        func.call @add_need(%114) : (i64) -> ()
        cf.br ^bb20
      ^bb19:
        cf.br ^bb20
      ^bb20:
      %115 = llvm.load %89 : !llvm.ptr -> i64
      %116 = llvm.mlir.addressof @MOD : !llvm.ptr
      %117 = llvm.load %116 : !llvm.ptr -> i64
      %118 = arith.divsi %115, %117 : i64
      llvm.store %118, %89 : i64, !llvm.ptr
      %119 = llvm.load %91 : !llvm.ptr -> i64
      %120 = llvm.mlir.addressof @MOD : !llvm.ptr
      %121 = llvm.load %120 : !llvm.ptr -> i64
      %122 = arith.divsi %119, %121 : i64
      llvm.store %122, %91 : i64, !llvm.ptr
      cf.br ^bb15
    ^bb17:
    func.return
  }
  func.func @sort_targets() -> () {
    %123 = arith.constant 1 : i32
    %124 = arith.extsi %123 : i32 to i64
    %125 = llvm.mlir.constant(1 : i64) : i64
    %126 = llvm.alloca %125 x i64 : (i64) -> !llvm.ptr
    llvm.store %124, %126 : i64, !llvm.ptr
    cf.br ^bb21
    ^bb21:
    %127 = llvm.load %126 : !llvm.ptr -> i64
    %128 = llvm.mlir.addressof @NT : !llvm.ptr
    %129 = llvm.load %128 : !llvm.ptr -> i64
    %130 = arith.cmpi slt, %127, %129 : i64
    cf.cond_br %130, ^bb22, ^bb23
    ^bb22:
      %132 = llvm.mlir.addressof @TARGETS : !llvm.ptr
      %133 = llvm.load %132 : !llvm.ptr -> !llvm.ptr
      %134 = llvm.load %126 : !llvm.ptr -> i64
      %135 = llvm.getelementptr %133[%134] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %131 = llvm.load %135 : !llvm.ptr -> i64
      %136 = llvm.load %126 : !llvm.ptr -> i64
      %137 = arith.constant 1 : i32
      %139 = arith.extsi %137 : i32 to i64
      %138 = arith.subi %136, %139 : i64
      %140 = llvm.mlir.constant(1 : i64) : i64
      %141 = llvm.alloca %140 x i64 : (i64) -> !llvm.ptr
      llvm.store %138, %141 : i64, !llvm.ptr
      cf.br ^bb24
      ^bb24:
      %142 = llvm.load %141 : !llvm.ptr -> i64
      %143 = arith.constant 0 : i32
      %145 = arith.extsi %143 : i32 to i64
      %144 = arith.cmpi sge, %142, %145 : i64
      %146 = scf.if %144 -> (i1) {
        %148 = llvm.mlir.addressof @TARGETS : !llvm.ptr
        %149 = llvm.load %148 : !llvm.ptr -> !llvm.ptr
        %150 = llvm.load %141 : !llvm.ptr -> i64
        %151 = llvm.getelementptr %149[%150] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        %147 = llvm.load %151 : !llvm.ptr -> i64
        %152 = arith.cmpi sgt, %147, %131 : i64
        scf.yield %152 : i1
      } else {
        %153 = arith.constant false
        scf.yield %153 : i1
      }
      cf.cond_br %146, ^bb25, ^bb26
      ^bb25:
        %155 = llvm.mlir.addressof @TARGETS : !llvm.ptr
        %156 = llvm.load %155 : !llvm.ptr -> !llvm.ptr
        %157 = llvm.load %141 : !llvm.ptr -> i64
        %158 = llvm.getelementptr %156[%157] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        %154 = llvm.load %158 : !llvm.ptr -> i64
        %159 = llvm.mlir.addressof @TARGETS : !llvm.ptr
        %160 = llvm.load %159 : !llvm.ptr -> !llvm.ptr
        %161 = llvm.load %141 : !llvm.ptr -> i64
        %162 = arith.constant 1 : i32
        %164 = arith.extsi %162 : i32 to i64
        %163 = arith.addi %161, %164 : i64
        %165 = llvm.getelementptr %160[%163] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        llvm.store %154, %165 : i64, !llvm.ptr
        %166 = llvm.load %141 : !llvm.ptr -> i64
        %167 = arith.constant 1 : i32
        %169 = arith.extsi %167 : i32 to i64
        %168 = arith.subi %166, %169 : i64
        llvm.store %168, %141 : i64, !llvm.ptr
        cf.br ^bb24
      ^bb26:
      %170 = llvm.mlir.addressof @TARGETS : !llvm.ptr
      %171 = llvm.load %170 : !llvm.ptr -> !llvm.ptr
      %172 = llvm.load %141 : !llvm.ptr -> i64
      %173 = arith.constant 1 : i32
      %175 = arith.extsi %173 : i32 to i64
      %174 = arith.addi %172, %175 : i64
      %176 = llvm.getelementptr %171[%174] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      llvm.store %131, %176 : i64, !llvm.ptr
      %177 = llvm.load %126 : !llvm.ptr -> i64
      %178 = arith.constant 1 : i32
      %180 = arith.extsi %178 : i32 to i64
      %179 = arith.addi %177, %180 : i64
      llvm.store %179, %126 : i64, !llvm.ptr
      cf.br ^bb21
    ^bb23:
    func.return
  }
  func.func @index_of(%arg0: i64) -> i64 {
    %181 = arith.constant 0 : i32
    %182 = arith.extsi %181 : i32 to i64
    %183 = llvm.mlir.constant(1 : i64) : i64
    %184 = llvm.alloca %183 x i64 : (i64) -> !llvm.ptr
    llvm.store %182, %184 : i64, !llvm.ptr
    %185 = llvm.mlir.addressof @NT : !llvm.ptr
    %186 = llvm.load %185 : !llvm.ptr -> i64
    %187 = arith.constant 1 : i32
    %189 = arith.extsi %187 : i32 to i64
    %188 = arith.subi %186, %189 : i64
    %190 = llvm.mlir.constant(1 : i64) : i64
    %191 = llvm.alloca %190 x i64 : (i64) -> !llvm.ptr
    llvm.store %188, %191 : i64, !llvm.ptr
    cf.br ^bb27
    ^bb27:
    %192 = llvm.load %184 : !llvm.ptr -> i64
    %193 = llvm.load %191 : !llvm.ptr -> i64
    %194 = arith.cmpi sle, %192, %193 : i64
    cf.cond_br %194, ^bb28, ^bb29
    ^bb28:
      %195 = llvm.load %184 : !llvm.ptr -> i64
      %196 = llvm.load %191 : !llvm.ptr -> i64
      %197 = arith.addi %195, %196 : i64
      %198 = arith.constant 2 : i32
      %200 = arith.extsi %198 : i32 to i64
      %199 = arith.divsi %197, %200 : i64
      %202 = llvm.mlir.addressof @TARGETS : !llvm.ptr
      %203 = llvm.load %202 : !llvm.ptr -> !llvm.ptr
      %204 = llvm.getelementptr %203[%199] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %201 = llvm.load %204 : !llvm.ptr -> i64
      %205 = arith.cmpi eq, %201, %arg0 : i64
      cf.cond_br %205, ^bb30, ^bb31
      ^bb30:
        func.return %199 : i64
      ^bb31:
        cf.br ^bb32
      ^bb32:
      %206 = arith.cmpi slt, %201, %arg0 : i64
      cf.cond_br %206, ^bb33, ^bb34
      ^bb33:
        %207 = arith.constant 1 : i32
        %209 = arith.extsi %207 : i32 to i64
        %208 = arith.addi %199, %209 : i64
        llvm.store %208, %184 : i64, !llvm.ptr
        cf.br ^bb35
      ^bb34:
        %210 = arith.constant 1 : i32
        %212 = arith.extsi %210 : i32 to i64
        %211 = arith.subi %199, %212 : i64
        llvm.store %211, %191 : i64, !llvm.ptr
        cf.br ^bb35
      ^bb35:
      cf.br ^bb27
    ^bb29:
    %213 = arith.constant 1 : i32
    %215 = arith.constant 0 : i32
    %214 = arith.subi %215, %213 : i32
    %216 = arith.extsi %214 : i32 to i64
    func.return %216 : i64
  }
  func.func @small_binom(%arg0: i64, %arg1: i64) -> i64 {
    %217 = arith.constant 0 : i32
    %219 = arith.extsi %217 : i32 to i64
    %218 = arith.cmpi slt, %arg1, %219 : i64
    %220 = scf.if %218 -> (i1) {
      %221 = arith.constant true
      scf.yield %221 : i1
    } else {
      %222 = arith.cmpi sgt, %arg1, %arg0 : i64
      scf.yield %222 : i1
    }
    cf.cond_br %220, ^bb36, ^bb37
    ^bb36:
      %223 = arith.constant 0 : i32
      %224 = arith.extsi %223 : i32 to i64
      func.return %224 : i64
    ^bb37:
      cf.br ^bb38
    ^bb38:
    %225 = func.call @index_of(%arg0) : (i64) -> i64
    %226 = func.call @index_of(%arg1) : (i64) -> i64
    %228 = arith.subi %arg0, %arg1 : i64
    %227 = func.call @index_of(%228) : (i64) -> i64
    %229 = arith.constant 0 : i32
    %231 = arith.extsi %229 : i32 to i64
    %230 = arith.cmpi slt, %225, %231 : i64
    %232 = scf.if %230 -> (i1) {
      %233 = arith.constant true
      scf.yield %233 : i1
    } else {
      %234 = arith.constant 0 : i32
      %236 = arith.extsi %234 : i32 to i64
      %235 = arith.cmpi slt, %226, %236 : i64
      scf.yield %235 : i1
    }
    %237 = scf.if %232 -> (i1) {
      %238 = arith.constant true
      scf.yield %238 : i1
    } else {
      %239 = arith.constant 0 : i32
      %241 = arith.extsi %239 : i32 to i64
      %240 = arith.cmpi slt, %227, %241 : i64
      scf.yield %240 : i1
    }
    cf.cond_br %237, ^bb39, ^bb40
    ^bb39:
      %242 = arith.constant 0 : i32
      %243 = arith.extsi %242 : i32 to i64
      func.return %243 : i64
    ^bb40:
      cf.br ^bb41
    ^bb41:
    %245 = llvm.mlir.addressof @FACT : !llvm.ptr
    %246 = llvm.load %245 : !llvm.ptr -> !llvm.ptr
    %247 = llvm.getelementptr %246[%225] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    %244 = llvm.load %247 : !llvm.ptr -> i64
    %248 = arith.extsi %244 : i64 to i128
    %250 = llvm.mlir.addressof @INVFACT : !llvm.ptr
    %251 = llvm.load %250 : !llvm.ptr -> !llvm.ptr
    %252 = llvm.getelementptr %251[%226] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    %249 = llvm.load %252 : !llvm.ptr -> i64
    %253 = arith.extsi %249 : i64 to i128
    %255 = arith.trunci %248 : i128 to i64
    %256 = arith.trunci %253 : i128 to i64
    %254 = arith.muli %255, %256 : i64
    %257 = llvm.mlir.addressof @MOD : !llvm.ptr
    %258 = llvm.load %257 : !llvm.ptr -> i64
    %259 = arith.extsi %258 : i64 to i128
    %261 = arith.trunci %259 : i128 to i64
    %260 = arith.remsi %254, %261 : i64
    %263 = llvm.mlir.addressof @INVFACT : !llvm.ptr
    %264 = llvm.load %263 : !llvm.ptr -> !llvm.ptr
    %265 = llvm.getelementptr %264[%227] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    %262 = llvm.load %265 : !llvm.ptr -> i64
    %266 = arith.extsi %262 : i64 to i128
    %268 = arith.trunci %266 : i128 to i64
    %267 = arith.muli %260, %268 : i64
    %269 = llvm.mlir.addressof @MOD : !llvm.ptr
    %270 = llvm.load %269 : !llvm.ptr -> i64
    %271 = arith.extsi %270 : i64 to i128
    %273 = arith.trunci %271 : i128 to i64
    %272 = arith.remsi %267, %273 : i64
    func.return %272 : i64
  }
  func.func @lucas_binom(%arg0: i64, %arg1: i64) -> i64 {
    %274 = llvm.mlir.constant(1 : i64) : i64
    %275 = llvm.alloca %274 x i64 : (i64) -> !llvm.ptr
    llvm.store %arg0, %275 : i64, !llvm.ptr
    %276 = llvm.mlir.constant(1 : i64) : i64
    %277 = llvm.alloca %276 x i64 : (i64) -> !llvm.ptr
    llvm.store %arg1, %277 : i64, !llvm.ptr
    %278 = arith.constant 1 : i32
    %279 = arith.extsi %278 : i32 to i64
    %280 = llvm.mlir.constant(1 : i64) : i64
    %281 = llvm.alloca %280 x i64 : (i64) -> !llvm.ptr
    llvm.store %279, %281 : i64, !llvm.ptr
    cf.br ^bb42
    ^bb42:
    %282 = llvm.load %275 : !llvm.ptr -> i64
    %283 = arith.constant 0 : i32
    %285 = arith.extsi %283 : i32 to i64
    %284 = arith.cmpi sgt, %282, %285 : i64
    %286 = scf.if %284 -> (i1) {
      %287 = arith.constant true
      scf.yield %287 : i1
    } else {
      %288 = llvm.load %277 : !llvm.ptr -> i64
      %289 = arith.constant 0 : i32
      %291 = arith.extsi %289 : i32 to i64
      %290 = arith.cmpi sgt, %288, %291 : i64
      scf.yield %290 : i1
    }
    cf.cond_br %286, ^bb43, ^bb44
    ^bb43:
      %292 = llvm.load %275 : !llvm.ptr -> i64
      %293 = llvm.mlir.addressof @MOD : !llvm.ptr
      %294 = llvm.load %293 : !llvm.ptr -> i64
      %295 = arith.remsi %292, %294 : i64
      %296 = llvm.load %277 : !llvm.ptr -> i64
      %297 = llvm.mlir.addressof @MOD : !llvm.ptr
      %298 = llvm.load %297 : !llvm.ptr -> i64
      %299 = arith.remsi %296, %298 : i64
      %300 = arith.cmpi sgt, %299, %295 : i64
      cf.cond_br %300, ^bb45, ^bb46
      ^bb45:
        %301 = arith.constant 0 : i32
        %302 = arith.extsi %301 : i32 to i64
        func.return %302 : i64
      ^bb46:
        cf.br ^bb47
      ^bb47:
      %303 = llvm.load %281 : !llvm.ptr -> i64
      %304 = arith.extsi %303 : i64 to i128
      %305 = func.call @small_binom(%295, %299) : (i64, i64) -> i64
      %306 = arith.extsi %305 : i64 to i128
      %308 = arith.trunci %304 : i128 to i64
      %309 = arith.trunci %306 : i128 to i64
      %307 = arith.muli %308, %309 : i64
      %310 = llvm.mlir.addressof @MOD : !llvm.ptr
      %311 = llvm.load %310 : !llvm.ptr -> i64
      %312 = arith.extsi %311 : i64 to i128
      %314 = arith.trunci %312 : i128 to i64
      %313 = arith.remsi %307, %314 : i64
      llvm.store %313, %281 : i64, !llvm.ptr
      %315 = llvm.load %275 : !llvm.ptr -> i64
      %316 = llvm.mlir.addressof @MOD : !llvm.ptr
      %317 = llvm.load %316 : !llvm.ptr -> i64
      %318 = arith.divsi %315, %317 : i64
      llvm.store %318, %275 : i64, !llvm.ptr
      %319 = llvm.load %277 : !llvm.ptr -> i64
      %320 = llvm.mlir.addressof @MOD : !llvm.ptr
      %321 = llvm.load %320 : !llvm.ptr -> i64
      %322 = arith.divsi %319, %321 : i64
      llvm.store %322, %277 : i64, !llvm.ptr
      cf.br ^bb42
    ^bb44:
    %323 = llvm.load %281 : !llvm.ptr -> i64
    func.return %323 : i64
  }
  func.func @C_mod(%arg0: i64) -> i64 {
    %325 = arith.constant 2 : i32
    %327 = arith.extsi %325 : i32 to i64
    %326 = arith.muli %327, %arg0 : i64
    %324 = func.call @lucas_binom(%326, %arg0) : (i64, i64) -> i64
    %328 = llvm.mlir.addressof @MOD : !llvm.ptr
    %329 = llvm.load %328 : !llvm.ptr -> i64
    %330 = arith.remsi %arg0, %329 : i64
    %331 = arith.constant 3 : i32
    %333 = arith.extsi %331 : i32 to i64
    %332 = arith.muli %333, %330 : i64
    %334 = llvm.mlir.addressof @MOD : !llvm.ptr
    %335 = llvm.load %334 : !llvm.ptr -> i64
    %336 = arith.remsi %332, %335 : i64
    %337 = arith.muli %336, %330 : i64
    %338 = arith.constant 2 : i32
    %340 = arith.extsi %338 : i32 to i64
    %339 = arith.muli %340, %330 : i64
    %341 = arith.addi %337, %339 : i64
    %342 = arith.constant 7 : i32
    %344 = arith.extsi %342 : i32 to i64
    %343 = arith.addi %341, %344 : i64
    %345 = llvm.mlir.addressof @MOD : !llvm.ptr
    %346 = llvm.load %345 : !llvm.ptr -> i64
    %347 = arith.remsi %343, %346 : i64
    %348 = arith.constant 8 : i32
    %350 = arith.extsi %348 : i32 to i64
    %349 = arith.muli %350, %324 : i64
    %351 = arith.subi %349, %347 : i64
    %352 = llvm.mlir.addressof @MOD : !llvm.ptr
    %353 = llvm.load %352 : !llvm.ptr -> i64
    %354 = arith.remsi %351, %353 : i64
    %355 = llvm.mlir.constant(1 : i64) : i64
    %356 = llvm.alloca %355 x i64 : (i64) -> !llvm.ptr
    llvm.store %354, %356 : i64, !llvm.ptr
    %357 = llvm.load %356 : !llvm.ptr -> i64
    %358 = arith.constant 0 : i32
    %360 = arith.extsi %358 : i32 to i64
    %359 = arith.cmpi slt, %357, %360 : i64
    cf.cond_br %359, ^bb48, ^bb49
    ^bb48:
      %361 = llvm.load %356 : !llvm.ptr -> i64
      %362 = llvm.mlir.addressof @MOD : !llvm.ptr
      %363 = llvm.load %362 : !llvm.ptr -> i64
      %364 = arith.addi %361, %363 : i64
      llvm.store %364, %356 : i64, !llvm.ptr
      cf.br ^bb50
    ^bb49:
      cf.br ^bb50
    ^bb50:
    %365 = llvm.load %356 : !llvm.ptr -> i64
    func.return %365 : i64
  }
  func.func @main() -> i32 {
    %367 = arith.constant 91 : i32
    %368 = arith.constant 8 : i32
    %369 = arith.extsi %367 : i32 to i64
    %370 = arith.extsi %368 : i32 to i64
    %366 = func.call @calloc(%369, %370) : (i64, i64) -> !llvm.ptr
    %371 = llvm.mlir.zero : !llvm.ptr
    %372 = llvm.icmp "eq" %366, %371 : !llvm.ptr
    cf.cond_br %372, ^bb51, ^bb52
    ^bb51:
      %373 = arith.constant 1 : i32
      func.return %373 : i32
    ^bb52:
      cf.br ^bb53
    ^bb53:
    %374 = arith.constant 0 : i32
    %375 = arith.constant 0 : i32
    %376 = arith.extsi %374 : i32 to i64
    %377 = arith.extsi %375 : i32 to i64
    %378 = llvm.getelementptr %366[%377] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %376, %378 : i64, !llvm.ptr
    %379 = arith.constant 1 : i32
    %380 = arith.constant 1 : i32
    %381 = arith.extsi %379 : i32 to i64
    %382 = arith.extsi %380 : i32 to i64
    %383 = llvm.getelementptr %366[%382] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %381, %383 : i64, !llvm.ptr
    %384 = arith.constant 2 : i32
    %385 = arith.extsi %384 : i32 to i64
    %386 = llvm.mlir.constant(1 : i64) : i64
    %387 = llvm.alloca %386 x i64 : (i64) -> !llvm.ptr
    llvm.store %385, %387 : i64, !llvm.ptr
    cf.br ^bb54
    ^bb54:
    %388 = llvm.load %387 : !llvm.ptr -> i64
    %389 = arith.constant 90 : i32
    %391 = arith.extsi %389 : i32 to i64
    %390 = arith.cmpi sle, %388, %391 : i64
    cf.cond_br %390, ^bb55, ^bb56
    ^bb55:
      %393 = llvm.load %387 : !llvm.ptr -> i64
      %394 = arith.constant 1 : i32
      %396 = arith.extsi %394 : i32 to i64
      %395 = arith.subi %393, %396 : i64
      %397 = llvm.getelementptr %366[%395] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %392 = llvm.load %397 : !llvm.ptr -> i64
      %399 = llvm.load %387 : !llvm.ptr -> i64
      %400 = arith.constant 2 : i32
      %402 = arith.extsi %400 : i32 to i64
      %401 = arith.subi %399, %402 : i64
      %403 = llvm.getelementptr %366[%401] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %398 = llvm.load %403 : !llvm.ptr -> i64
      %404 = arith.addi %392, %398 : i64
      %405 = llvm.load %387 : !llvm.ptr -> i64
      %406 = llvm.getelementptr %366[%405] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      llvm.store %404, %406 : i64, !llvm.ptr
      %407 = llvm.load %387 : !llvm.ptr -> i64
      %408 = arith.constant 1 : i32
      %410 = arith.extsi %408 : i32 to i64
      %409 = arith.addi %407, %410 : i64
      llvm.store %409, %387 : i64, !llvm.ptr
      cf.br ^bb54
    ^bb56:
    %412 = llvm.mlir.addressof @NEED_CAP : !llvm.ptr
    %413 = llvm.load %412 : !llvm.ptr -> i64
    %414 = arith.constant 8 : i32
    %415 = arith.extsi %414 : i32 to i64
    %411 = func.call @calloc(%413, %415) : (i64, i64) -> !llvm.ptr
    %416 = llvm.mlir.addressof @TARGETS : !llvm.ptr
    llvm.store %411, %416 : !llvm.ptr, !llvm.ptr
    %418 = llvm.mlir.addressof @NEED_CAP : !llvm.ptr
    %419 = llvm.load %418 : !llvm.ptr -> i64
    %420 = arith.constant 8 : i32
    %421 = arith.extsi %420 : i32 to i64
    %417 = func.call @calloc(%419, %421) : (i64, i64) -> !llvm.ptr
    %422 = llvm.mlir.addressof @FACT : !llvm.ptr
    llvm.store %417, %422 : !llvm.ptr, !llvm.ptr
    %424 = llvm.mlir.addressof @NEED_CAP : !llvm.ptr
    %425 = llvm.load %424 : !llvm.ptr -> i64
    %426 = arith.constant 8 : i32
    %427 = arith.extsi %426 : i32 to i64
    %423 = func.call @calloc(%425, %427) : (i64, i64) -> !llvm.ptr
    %428 = llvm.mlir.addressof @INVFACT : !llvm.ptr
    llvm.store %423, %428 : !llvm.ptr, !llvm.ptr
    %429 = llvm.mlir.addressof @TARGETS : !llvm.ptr
    %430 = llvm.load %429 : !llvm.ptr -> !llvm.ptr
    %431 = llvm.mlir.zero : !llvm.ptr
    %432 = llvm.icmp "eq" %430, %431 : !llvm.ptr
    %433 = scf.if %432 -> (i1) {
      %434 = arith.constant true
      scf.yield %434 : i1
    } else {
      %435 = llvm.mlir.addressof @FACT : !llvm.ptr
      %436 = llvm.load %435 : !llvm.ptr -> !llvm.ptr
      %437 = llvm.mlir.zero : !llvm.ptr
      %438 = llvm.icmp "eq" %436, %437 : !llvm.ptr
      scf.yield %438 : i1
    }
    %439 = scf.if %433 -> (i1) {
      %440 = arith.constant true
      scf.yield %440 : i1
    } else {
      %441 = llvm.mlir.addressof @INVFACT : !llvm.ptr
      %442 = llvm.load %441 : !llvm.ptr -> !llvm.ptr
      %443 = llvm.mlir.zero : !llvm.ptr
      %444 = llvm.icmp "eq" %442, %443 : !llvm.ptr
      scf.yield %444 : i1
    }
    cf.cond_br %439, ^bb57, ^bb58
    ^bb57:
      %445 = arith.constant 1 : i32
      func.return %445 : i32
    ^bb58:
      cf.br ^bb59
    ^bb59:
    %447 = arith.constant 0 : i32
    %448 = arith.extsi %447 : i32 to i64
    func.call @add_need(%448) : (i64) -> ()
    %450 = arith.constant 1 : i32
    %451 = arith.extsi %450 : i32 to i64
    func.call @add_need(%451) : (i64) -> ()
    %452 = arith.constant 2 : i32
    %453 = arith.extsi %452 : i32 to i64
    llvm.store %453, %387 : i64, !llvm.ptr
    cf.br ^bb60
    ^bb60:
    %454 = llvm.load %387 : !llvm.ptr -> i64
    %455 = arith.constant 90 : i32
    %457 = arith.extsi %455 : i32 to i64
    %456 = arith.cmpi sle, %454, %457 : i64
    cf.cond_br %456, ^bb61, ^bb62
    ^bb61:
      %460 = llvm.load %387 : !llvm.ptr -> i64
      %461 = llvm.getelementptr %366[%460] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %459 = llvm.load %461 : !llvm.ptr -> i64
      func.call @mark_binom_needs(%459) : (i64) -> ()
      %462 = llvm.load %387 : !llvm.ptr -> i64
      %463 = arith.constant 1 : i32
      %465 = arith.extsi %463 : i32 to i64
      %464 = arith.addi %462, %465 : i64
      llvm.store %464, %387 : i64, !llvm.ptr
      cf.br ^bb60
    ^bb62:
    %467 = arith.constant 1 : i32
    %468 = arith.extsi %467 : i32 to i64
    func.call @mark_binom_needs(%468) : (i64) -> ()
    %470 = arith.constant 2 : i32
    %471 = arith.extsi %470 : i32 to i64
    func.call @mark_binom_needs(%471) : (i64) -> ()
    %473 = arith.constant 10 : i32
    %474 = arith.extsi %473 : i32 to i64
    func.call @mark_binom_needs(%474) : (i64) -> ()
    func.call @sort_targets() : () -> ()
    %477 = llvm.mlir.addressof @TARGETS : !llvm.ptr
    %478 = llvm.load %477 : !llvm.ptr -> !llvm.ptr
    %479 = llvm.mlir.addressof @NT : !llvm.ptr
    %480 = llvm.load %479 : !llvm.ptr -> i64
    %481 = arith.constant 1 : i32
    %483 = arith.extsi %481 : i32 to i64
    %482 = arith.subi %480, %483 : i64
    %484 = llvm.getelementptr %478[%482] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    %476 = llvm.load %484 : !llvm.ptr -> i64
    %485 = arith.constant 1 : i32
    %486 = arith.extsi %485 : i32 to i64
    %487 = llvm.mlir.constant(1 : i64) : i64
    %488 = llvm.alloca %487 x i64 : (i64) -> !llvm.ptr
    llvm.store %486, %488 : i64, !llvm.ptr
    %489 = arith.constant 0 : i32
    %490 = arith.extsi %489 : i32 to i64
    %491 = llvm.mlir.constant(1 : i64) : i64
    %492 = llvm.alloca %491 x i64 : (i64) -> !llvm.ptr
    llvm.store %490, %492 : i64, !llvm.ptr
    %493 = arith.constant 1 : i32
    %494 = llvm.mlir.addressof @FACT : !llvm.ptr
    %495 = llvm.load %494 : !llvm.ptr -> !llvm.ptr
    %496 = arith.constant 0 : i32
    %497 = arith.extsi %493 : i32 to i64
    %498 = arith.extsi %496 : i32 to i64
    %499 = llvm.getelementptr %495[%498] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %497, %499 : i64, !llvm.ptr
    %500 = arith.constant 1 : i32
    %501 = llvm.mlir.addressof @INVFACT : !llvm.ptr
    %502 = llvm.load %501 : !llvm.ptr -> !llvm.ptr
    %503 = arith.constant 0 : i32
    %504 = arith.extsi %500 : i32 to i64
    %505 = arith.extsi %503 : i32 to i64
    %506 = llvm.getelementptr %502[%505] : (!llvm.ptr, i64) -> !llvm.ptr, i64
    llvm.store %504, %506 : i64, !llvm.ptr
    %507 = arith.constant 1 : i32
    %508 = arith.extsi %507 : i32 to i64
    llvm.store %508, %492 : i64, !llvm.ptr
    %509 = arith.constant 1 : i32
    %510 = arith.extsi %509 : i32 to i64
    llvm.store %510, %387 : i64, !llvm.ptr
    cf.br ^bb63
    ^bb63:
    %511 = llvm.load %387 : !llvm.ptr -> i64
    %512 = arith.cmpi sle, %511, %476 : i64
    cf.cond_br %512, ^bb64, ^bb65
    ^bb64:
      %513 = llvm.load %488 : !llvm.ptr -> i64
      %514 = arith.extsi %513 : i64 to i128
      %515 = llvm.load %387 : !llvm.ptr -> i64
      %516 = arith.extsi %515 : i64 to i128
      %518 = arith.trunci %514 : i128 to i64
      %519 = arith.trunci %516 : i128 to i64
      %517 = arith.muli %518, %519 : i64
      %520 = llvm.mlir.addressof @MOD : !llvm.ptr
      %521 = llvm.load %520 : !llvm.ptr -> i64
      %522 = arith.extsi %521 : i64 to i128
      %524 = arith.trunci %522 : i128 to i64
      %523 = arith.remsi %517, %524 : i64
      llvm.store %523, %488 : i64, !llvm.ptr
      %525 = llvm.load %492 : !llvm.ptr -> i64
      %526 = llvm.mlir.addressof @NT : !llvm.ptr
      %527 = llvm.load %526 : !llvm.ptr -> i64
      %528 = arith.cmpi slt, %525, %527 : i64
      %529 = scf.if %528 -> (i1) {
        %531 = llvm.mlir.addressof @TARGETS : !llvm.ptr
        %532 = llvm.load %531 : !llvm.ptr -> !llvm.ptr
        %533 = llvm.load %492 : !llvm.ptr -> i64
        %534 = llvm.getelementptr %532[%533] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        %530 = llvm.load %534 : !llvm.ptr -> i64
        %535 = llvm.load %387 : !llvm.ptr -> i64
        %536 = arith.cmpi eq, %530, %535 : i64
        scf.yield %536 : i1
      } else {
        %537 = arith.constant false
        scf.yield %537 : i1
      }
      cf.cond_br %529, ^bb66, ^bb67
      ^bb66:
        %538 = llvm.load %488 : !llvm.ptr -> i64
        %539 = llvm.mlir.addressof @FACT : !llvm.ptr
        %540 = llvm.load %539 : !llvm.ptr -> !llvm.ptr
        %541 = llvm.load %492 : !llvm.ptr -> i64
        %542 = llvm.getelementptr %540[%541] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        llvm.store %538, %542 : i64, !llvm.ptr
        %544 = llvm.load %488 : !llvm.ptr -> i64
        %545 = llvm.mlir.addressof @MOD : !llvm.ptr
        %546 = llvm.load %545 : !llvm.ptr -> i64
        %547 = arith.constant 2 : i32
        %549 = arith.extsi %547 : i32 to i64
        %548 = arith.subi %546, %549 : i64
        %550 = llvm.mlir.addressof @MOD : !llvm.ptr
        %551 = llvm.load %550 : !llvm.ptr -> i64
        %543 = func.call @modpow(%544, %548, %551) : (i64, i64, i64) -> i64
        %552 = llvm.mlir.addressof @INVFACT : !llvm.ptr
        %553 = llvm.load %552 : !llvm.ptr -> !llvm.ptr
        %554 = llvm.load %492 : !llvm.ptr -> i64
        %555 = llvm.getelementptr %553[%554] : (!llvm.ptr, i64) -> !llvm.ptr, i64
        llvm.store %543, %555 : i64, !llvm.ptr
        %556 = llvm.load %492 : !llvm.ptr -> i64
        %557 = arith.constant 1 : i32
        %559 = arith.extsi %557 : i32 to i64
        %558 = arith.addi %556, %559 : i64
        llvm.store %558, %492 : i64, !llvm.ptr
        cf.br ^bb68
      ^bb67:
        cf.br ^bb68
      ^bb68:
      %560 = llvm.load %387 : !llvm.ptr -> i64
      %561 = arith.constant 1 : i32
      %563 = arith.extsi %561 : i32 to i64
      %562 = arith.addi %560, %563 : i64
      llvm.store %562, %387 : i64, !llvm.ptr
      cf.br ^bb63
    ^bb65:
    %564 = arith.constant 0 : i32
    %565 = arith.extsi %564 : i32 to i64
    %566 = llvm.mlir.constant(1 : i64) : i64
    %567 = llvm.alloca %566 x i64 : (i64) -> !llvm.ptr
    llvm.store %565, %567 : i64, !llvm.ptr
    %568 = arith.constant 2 : i32
    %569 = arith.extsi %568 : i32 to i64
    llvm.store %569, %387 : i64, !llvm.ptr
    cf.br ^bb69
    ^bb69:
    %570 = llvm.load %387 : !llvm.ptr -> i64
    %571 = arith.constant 90 : i32
    %573 = arith.extsi %571 : i32 to i64
    %572 = arith.cmpi sle, %570, %573 : i64
    cf.cond_br %572, ^bb70, ^bb71
    ^bb70:
      %574 = llvm.load %567 : !llvm.ptr -> i64
      %577 = llvm.load %387 : !llvm.ptr -> i64
      %578 = llvm.getelementptr %366[%577] : (!llvm.ptr, i64) -> !llvm.ptr, i64
      %576 = llvm.load %578 : !llvm.ptr -> i64
      %575 = func.call @C_mod(%576) : (i64) -> i64
      %579 = arith.addi %574, %575 : i64
      llvm.store %579, %567 : i64, !llvm.ptr
      %580 = llvm.load %567 : !llvm.ptr -> i64
      %581 = llvm.mlir.addressof @MOD : !llvm.ptr
      %582 = llvm.load %581 : !llvm.ptr -> i64
      %583 = arith.cmpi sge, %580, %582 : i64
      cf.cond_br %583, ^bb72, ^bb73
      ^bb72:
        %584 = llvm.load %567 : !llvm.ptr -> i64
        %585 = llvm.mlir.addressof @MOD : !llvm.ptr
        %586 = llvm.load %585 : !llvm.ptr -> i64
        %587 = arith.subi %584, %586 : i64
        llvm.store %587, %567 : i64, !llvm.ptr
        cf.br ^bb74
      ^bb73:
        cf.br ^bb74
      ^bb74:
      %588 = llvm.load %387 : !llvm.ptr -> i64
      %589 = arith.constant 1 : i32
      %591 = arith.extsi %589 : i32 to i64
      %590 = arith.addi %588, %591 : i64
      llvm.store %590, %387 : i64, !llvm.ptr
      cf.br ^bb69
    ^bb71:
    %592 = llvm.mlir.addressof @str_0 : !llvm.ptr
    %593 = llvm.load %567 : !llvm.ptr -> i64
    %594 = llvm.call @printf(%592, %593) vararg(!llvm.func<i32 (ptr, ...)>) : (!llvm.ptr, i64) -> i32
    func.call @free(%366) : (!llvm.ptr) -> ()
    %597 = llvm.mlir.addressof @TARGETS : !llvm.ptr
    %598 = llvm.load %597 : !llvm.ptr -> !llvm.ptr
    func.call @free(%598) : (!llvm.ptr) -> ()
    %600 = llvm.mlir.addressof @FACT : !llvm.ptr
    %601 = llvm.load %600 : !llvm.ptr -> !llvm.ptr
    func.call @free(%601) : (!llvm.ptr) -> ()
    %603 = llvm.mlir.addressof @INVFACT : !llvm.ptr
    %604 = llvm.load %603 : !llvm.ptr -> !llvm.ptr
    func.call @free(%604) : (!llvm.ptr) -> ()
    %605 = arith.constant 0 : i32
    func.return %605 : i32
  }
}