AtCoder Beginner Contest 354 E

https://atcoder.jp/contests/abc354/tasks/abc354_e

特に工夫もせずにグラフを作ります。それで十分間に合いました。

// Remove Pairs
#![allow(non_snake_case)]

use std::collections::HashMap;


//////////////////// library ////////////////////

fn read<T: std::str::FromStr>() -> T {
    let mut line = String::new();
    std::io::stdin().read_line(&mut line).ok();
    line.trim().parse().ok().unwrap()
}

fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    read::<String>().split_whitespace()
            .map(|e| e.parse().ok().unwrap()).collect()
}


//////////////////// Graph ////////////////////

type Node = usize;
type Edge = (Node, Node);

struct Graph {
    g: Vec<usize>
}

impl Graph {
    fn len(&self) -> usize {
        self.g.len()
    }
    
    fn edges(&self) -> Vec<Edge> {
        let mut edges: Vec<Edge> = vec![];
        for u in 0..self.len() {
            if self.g[u] == 0 {
                continue
            }
            for v in u+1..self.len() {
                if ((self.g[u] >> v) & 1) != 0 {
                    edges.push((u, v))
                }
            }
        }
        edges
    }
    
    fn is_isolated(&self) -> bool {
        self.g.iter().all(|&s| s == 0)
    }
    
    fn remove_node(&mut self, v: Node) -> usize {
        let s = self.g[v];
        for i in 0..self.len() {
            if ((s >> i) & 1) == 1 {
                self.g[i] -= 1 << v;
            }
        }
        self.g[v] = 0;
        s
    }
    
    fn resume(&mut self, v: Node, s: usize) {
        for i in 0..self.len() {
            if ((s >> i) & 1) == 1 {
                self.g[i] |= 1 << v
            }
        }
        self.g[v] = s
    }
}


//////////////////// process ////////////////////

type Card = (i32, i32);

fn read_card() -> Card {
    let v = read_vec();
    let (A, B) = (v[0], v[1]);
    (A, B)
}

fn read_input() -> Vec<Card> {
    let N = read();
    let cards: Vec<Card> = (0..N).map(|_| read_card()).collect();
    cards
}

fn add_edges(map: HashMap<i32, usize>, g: &mut Vec<usize>) {
    let N = g.len();
    for (_, s) in map.into_iter() {
        for i in 0..N {
            if ((s >> i) & 1) == 0 {
                continue
            }
            for j in 0..N {
                if i != j && ((s >> j) & 1) == 1 {
                    g[i] |= 1 << j
                }
            }
        }
    }
}

fn make_graph(cards: Vec<Card>) -> Graph {
    let N = cards.len();
    let mut map1: HashMap<i32, usize> = HashMap::new();
    let mut map2: HashMap<i32, usize> = HashMap::new();
    for (i, (A, B)) in cards.into_iter().enumerate() {
        let e1 = map1.entry(A).or_insert(0);
        *e1 |= 1 << i;
        let e2 = map2.entry(B).or_insert(0);
        *e2 |= 1 << i
    }
    let mut g: Vec<usize> = vec![0; N];
    add_edges(map1, &mut g);
    add_edges(map2, &mut g);
    Graph { g }
}

fn wins(s: usize, graph: &mut Graph, memo: &mut HashMap<usize, bool>) -> bool {
    if let Some(b) = memo.get(&s) {
        *b
    }
    else if graph.is_isolated() {
        false
    }
    else {
        for (u, v) in graph.edges().into_iter() {
            let su = graph.remove_node(u);
            let sv = graph.remove_node(v);
            let s1 = s - (1 << u) - (1 << v);
            let b1 = wins(s1, graph, memo);
            graph.resume(v, sv);
            graph.resume(u, su);
            if !b1 {
                memo.insert(s, true);
                return true
            }
        }
        memo.insert(s, false);
        false
    }
}

fn F(cards: Vec<Card>) -> bool {
    let N = cards.len();
    
    let mut graph = make_graph(cards);
    let mut memo: HashMap<usize, bool> = HashMap::new();
    wins((1 << N) - 1, &mut graph, &mut memo)
}

fn main() {
    let cards = read_input();
    println!("{}", (if F(cards) { "Takahashi" } else { "Aoki" }).to_string());
}

AtCoder Beginner Contest 354 D

https://atcoder.jp/contests/abc354/tasks/abc354_d

幅が4の倍数で高さが2の倍数の部分とそれ以外の3つの部分に分けて足し合わせます。

// AtCoder Wallpaper
#![allow(non_snake_case)]


//////////////////// library ////////////////////

fn read<T: std::str::FromStr>() -> T {
    let mut line = String::new();
    std::io::stdin().read_line(&mut line).ok();
    line.trim().parse().ok().unwrap()
}

fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    read::<String>().split_whitespace()
            .map(|e| e.parse().ok().unwrap()).collect()
}

fn div(n: i64, d: i64) -> i64 {
    if n < 0 {
        (n - d + 1) / d
    }
    else {
        n / d
    }
}

fn modulo(n: i64, d: i64) -> i64 {
    let r = n % d;
    if r < 0 {
        r + d
    }
    else {
        r
    }
}

fn divmod(n: i64, d: i64) -> (i64, i64) {
    (div(n, d), modulo(n, d))
}


//////////////////// process ////////////////////

fn read_input() -> (i64, i64, i64, i64) {
    let v = read_vec();
    let (A, B, C, D) = (v[0], v[1], v[2], v[3]);
    (A, B, C, D)
}

// y方向は偶数、x方向は任意
fn Fx(rx: i64, rdx: i64) -> i64 {
    let v: [i64; 4] = [3, 3, 1, 1];
    let mut s = 0;
    for x in 0..rdx {
        s += v[((x+rx)&3) as usize]
    }
    s
}

// x方向は4の倍数、y方向は任意
fn Fy(rdy: i64) -> i64 {
    4 * rdy
}

fn Fxy(rx: i64, ry: i64, rdx: i64, rdy: i64) -> i64 {
    let v: [[i64; 4]; 2] = [[2, 1, 0, 1], [1, 2, 1, 0]];
    let mut s = 0;
    for y in 0..rdy {
        for x in 0..rdx {
            s += v[((y+ry)&1) as usize][((x+rx)&3) as usize]
        }
    }
    s
}

fn F(A: i64, B: i64, C: i64, D: i64) -> i64 {
    let dx = C - A;
    let dy = D - B;
    let (qx, rdx) = divmod(dx, 4);
    let (qy, rdy) = divmod(dy, 2);
    let rx = modulo(A, 4);
    let ry = modulo(B, 2);
    let mut S = qx * qy * 8;
    S += Fx(rx, rdx) * qy;
    S += Fy(rdy) * qx;
    S += Fxy(rx, ry, rdx, rdy);
    S
}

fn main() {
    let (A, B, C, D) = read_input();
    println!("{}", F(A, B, C, D));
}

MojoでProject Euler 32

https://projecteuler.net/problem=32

問題をB進法に拡張します。
単にしらみつぶししてもいいのですが、それだけだと面白くないのでもう少し工夫します。B-1の剰余を考えると、各桁を足した和の剰余と同じになります。そうすると剰余の組み合わせが限られます。被乗数の剰余をx、乗数の剰余をyとすると、10進なら、

 x + y + xy \equiv 0

なので、

 (x - 1)(y - 1) \equiv 1

となって、x=0ならy=0に限られて、x=1なら対応するyはありません。
ただし、これはBが偶数の時で、奇数だと次のようになります。

 \displaystyle x + y + xy \equiv \frac{B-1}{2}

また、Bが偶数のときは、例えばB=10なら、2桁×3桁=4桁みたいなので、被乗数を決めると乗数は上から抑えられます。逆にBが奇数のときは下から抑えられます。なので、偶数と奇数でコードを分けるとよいです。

from collections import Set
import sys


#################### library ####################

def digits(n: Int, b: Int) -> List[Int]:
    var m = n;
    var ds = List[Int]()
    while m > 0:
        var d = m % b
        ds.append(d)
        m //= b
    return ds

# n以上でdの剰余がrの最小の整数
def ceil_mod(n: Int, r: Int, d: Int) -> Int:
    return (n+d-r-1) // d * d + r


#################### process ####################

fn find_num_digits_combs(B: Int) -> List[Tuple[Int, Int]]:
    var v = List[Tuple[Int, Int]]()
    for i in range(1, B//4+1):
        v.append((i, B//2-i))
    return v

fn find_mod_combs(B: Int) -> List[Tuple[Int, Int]]:
    # x + y + xy \equiv 0 (mod B-1)
    var v = List[Tuple[Int, Int]]()
    var sum_r = 0 if B % 2 == 0 else (B-1)//2
    for x in range(B-1):
        for y in range(B-1):
            if (x + y + x*y) % (B-1) == sum_r:
                v.append((x, y))
    return v

fn set_digits(n: Int, s: Int, B: Int) -> Int:
    var s1 = s
    try:
        var ds = digits(n, B)
        for d in ds:
            if ((s1 >> d[]) & 1) == 1:
                return -1
            else:
                s1 |= 1 << d[]
        return s1
    except:
        return -1

fn sum(s: Set[Int]) -> Int:
    var s1 = 0
    for n in s:
        s1 += n[]
    return s1

fn f_even(B: Int) raises -> Int:
    var s = Set[Int]()
    var v = find_num_digits_combs(B)
    var w = find_mod_combs(B)
    for t in v:
        var nd1 = t[].get[0, Int]()
        var nd2 = t[].get[1, Int]()
        var nd3 = B // 2 - 1
        for u in w:
            var r1 = u[].get[0, Int]()
            var r2 = u[].get[1, Int]()
            var first1 = ceil_mod(B**(nd1-1), r1, B-1)
            var first2 = ceil_mod(B**(nd2-1), r2, B-1)
            for n1 in range(first1, B**nd1, B-1):
                var s1 = set_digits(n1, 0, B)
                if s1 == -1:
                    continue
                # 100
                var last2 = B**nd3 // n1 + 1
                for n2 in range(first2, last2):
                    var n3 = n1 * n2
                    var s2 = set_digits(n2, s1, B)
                    if s2 == -1:
                        continue
                    var s3 = set_digits(n3, s2, B)
                    if s3 == (1 << B) - 2:
                        s.add(n3)
                        print(n1, n2, n3)
    return sum(s)

fn f_odd(B: Int) raises -> Int:
    var s = Set[Int]()
    var v = find_num_digits_combs(B)
    var w = find_mod_combs(B)
    for t in v:
        var nd1 = t[].get[0, Int]()
        var nd2 = t[].get[1, Int]()
        var nd3 = B // 2
        for u in w:
            var r1 = u[].get[0, Int]()
            var r2 = u[].get[1, Int]()
            var first1 = ceil_mod(B**(nd1-1), r1, B-1)
            for n1 in range(first1, B**nd1, B-1):
                var s1 = set_digits(n1, 0, B)
                if s1 == -1:
                    continue
                var first2 = ceil_mod(10**(nd3-1)//n1, r2, B-1)
                for n2 in range(first2, B**nd2):
                    var n3 = n1 * n2
                    var s2 = set_digits(n2, s1, B)
                    if s2 == -1:
                        continue
                    var s3 = set_digits(n3, s2, B)
                    if s3 == (1 << B) - 2:
                        s.add(n3)
                        print(n1, n2, n3)
    return sum(s)

fn f(B: Int) raises -> Int:
    if B % 2 == 0:
        return f_even(B)
    else:
        return f_odd(B)

fn main() raises:
    var args = sys.argv()
    var B = atol(args[1])
    print(f(B))

AtCoder Beginner Contest 353 F

https://atcoder.jp/contests/abc353/tasks/abc353_f

K = 1なら単なるマンハッタン距離です。
K > 1なら、例1のように両側から大きいタイルに出て、大きなタイル間の距離を調べます。そのとき斜めの成分とx軸、y軸のどちらかに分解します。斜め成分は一つ進むごとに2回タイルを通過します。それ以外の成分はK > 2なら2つ進むごとに角のタイルを使って4回タイルを通過しますが、K = 2の場合だけはそのまま突っ切って3回タイルを通過します。

// Tile Distance
#![allow(non_snake_case)]

use std::cmp::min;


//////////////////// library ////////////////////

fn read<T: std::str::FromStr>() -> T {
    let mut line = String::new();
    std::io::stdin().read_line(&mut line).ok();
    line.trim().parse().ok().unwrap()
}

fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    read::<String>().split_whitespace()
            .map(|e| e.parse().ok().unwrap()).collect()
}

fn div(n: i64, d: i64) -> i64 {
    if n < 0 {
        (n - d + 1) / d
    }
    else {
        n / d
    }
}

fn modulo(n: i64, d: i64) -> i64 {
    if n < 0 {
        let r = n % d;
        if r == 0 { r } else { r + d }
    }
    else {
        n % d
    }
}


//////////////////// Point ////////////////////

#[derive(Clone, Copy)]
struct Point {
    x: i64,
    y: i64
}

use std::ops::Sub;

impl Sub for Point {
    type Output = Self;
    
    fn sub(self, other: Self) -> Self {
        let x = self.x - other.x;
        let y = self.y - other.y;
        Point { x, y }
    }
}

impl Point {
    fn new(x: i64, y: i64) -> Point {
        Point { x, y }
    }
    
    fn read() -> Point {
        let v = read_vec();
        Point::new(v[0], v[1])
    }
}


//////////////////// process ////////////////////

fn read_input() -> (i64, Point, Point) {
    let K: i64 = read();
    let S = Point::read();
    let T = Point::read();
    (K, S, T)
}

fn F1(S: Point, T: Point) -> i64 {
    let d = S - T;
    d.x.abs() + d.y.abs()
}

fn is_large(pt: Point, K: i64) -> bool {
    (div(pt.x, K) + div(pt.y, K)) % 2 == 1
}

fn large_to_large(pt1: Point, pt2: Point, K: i64) -> i64 {
    let x1 = div(pt1.x, K);
    let y1 = div(pt1.y, K);
    let x2 = div(pt2.x, K);
    let y2 = div(pt2.y, K);
    let dx = (x1 - x2).abs();
    let dy = (y1 - y2).abs();
    let c = if K == 2 { 3 } else { 4 };
    (dx - dy).abs() * c / 2 + min(dx, dy) * 2
}

fn to_large(pt: Point, dir: i32, K: i64) -> (i64, Point) {
    if dir == 0 {
        let r = modulo(pt.x, K);
        (r + 1, Point::new(pt.x - K, pt.y))
    }
    else if dir == 1 {
        let r = modulo(pt.y, K);
        (K - r, Point::new(pt.x, pt.y + K))
    }
    else if dir == 2 {
        let r = modulo(pt.x, K);
        (K - r, Point::new(pt.x + K, pt.y))
    }
    else {
        let r = modulo(pt.y, K);
        (r + 1, Point::new(pt.x, pt.y - K))
    }
}

fn large_to_small(pt1: Point, pt2: Point, K: i64) -> i64 {
    let mut ds: Vec<i64> = vec![];
    for dir in 0..4 {
        let (d, pt3) = to_large(pt2, dir, K);
        ds.push(d + large_to_large(pt1, pt3, K))
    }
    ds.into_iter().min().unwrap()
}

fn small_to_small(pt1: Point, pt2: Point, K: i64) -> i64 {
    let mut ds: Vec<i64> = vec![F1(pt1, pt2)];
    for dir1 in 0..4 {
        for dir2 in 0..4 {
            let (d1, pt3) = to_large(pt1, dir1, K);
            let (d2, pt4) = to_large(pt2, dir2, K);
            ds.push(d1 + large_to_large(pt3, pt4, K) + d2)
        }
    }
    ds.into_iter().min().unwrap()
}

fn F2(K: i64, S: Point, T:Point) -> i64 {
    if is_large(S, K) {
        if is_large(T, K) {
            large_to_large(S, T, K)
        }
        else {
            large_to_small(S, T, K)
        }
    }
    else {
        if is_large(T, K) {
            large_to_small(T, S, K)
        }
        else {
            small_to_small(S, T, K)
        }
    }
}

fn F(K: i64, S: Point, T: Point) -> i64 {
    if K == 1 {
        F1(S, T)
    }
    else {
        F2(K, S, T)
    }
}

fn main() {
    let (K, S, T) = read_input();
    println!("{}", F(K, S, T))
}

AtCoder Beginner Contest 353 E

https://atcoder.jp/contests/abc353/tasks/abc353_e

木を作ればよいです。例1なら、

a(3)┓
    ┣b(2)┓
    ┃    ┗c(1)
    ┗rc(1)

のような木を作ります。数字は文字列の個数です。
Pythonで書いてAIにRustにしてもらいましたが、間違いが多くて修正するのが大変でした。

// Yet Another Sigma Problem
#![allow(non_snake_case)]

use std::fmt;
use std::cmp::min;


//////////////////// library ////////////////////

fn read<T: std::str::FromStr>() -> T {
    let mut line = String::new();
    std::io::stdin().read_line(&mut line).ok();
    line.trim().parse().ok().unwrap()
}

fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    read::<String>().split_whitespace()
            .map(|e| e.parse().ok().unwrap()).collect()
}


//////////////////// Node ////////////////////

struct Node {
    str: String,
    num: i64,
    children: Vec<Node>,
}

impl Node {
    fn new(s: &str) -> Node {
        Node {
            str: s.to_string(),
            num: 1,
            children: Vec::new(),
        }
    }
    
    fn insert(&mut self, s: &str) {
        self.num += 1;
        let mut length = std::usize::MAX;
        let common_length = min(s.len(), self.str.len());
        for i in 0..common_length {
            if s.as_bytes()[i] != self.str.as_bytes()[i] {
                length = i;
                break
            }
        }
        
        if length == std::usize::MAX {
            if s.len() == self.str.len() {
                return
            }
            else if s.len() < self.str.len() {
                let old_str = self.str.clone();
                self.str = s.to_string();
                let mut node = Node::new(&old_str[s.len()..]);
                node.num = self.num - 1;
                node.children.append(&mut self.children);
                self.children = vec![node];
            }
            else {
                let subs = &s[self.str.len()..];
                for child in &mut self.children {
                    if child.str.as_bytes()[0] == subs.as_bytes()[0] {
                        child.insert(subs);
                        return;
                    }
                }
                self.children.push(Node::new(subs));
            }
        }
        else {
            let old_str = self.str.clone();
            self.str = s[..length].to_string();
            let mut node1 = Node::new(&old_str[length..]);
            node1.num = self.num - 1;
            node1.children.append(&mut self.children);
            let node2 = Node::new(&s[length..]);
            self.children = vec![node1, node2];
        }
    }
    
    fn sum(&self) -> i64 {
        let s1 = self.str.len() as i64 * self.num * (self.num - 1) / 2;
        let s2: i64 = self.children.iter().map(|c| c.sum()).sum();
        s1 + s2
    }
}

impl fmt::Display for Node {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = format!("{}({})", self.str, self.num);
        let v: Vec<String> = self.children.iter()
            .flat_map(|c| format!("{}", c).split('\n').map(|s1| format!("  {}", s1)).collect::<Vec<String>>())
            .collect();
        write!(f, "{}\n{}", s, v.join("\n"))
    }
}


//////////////////// Tree ////////////////////

struct Tree {
    children: Vec<Node>
}

impl Tree {
    fn new() -> Tree {
        Tree { children: vec![] }
    }
    
    fn insert(&mut self, s: String) {
        for c in self.children.iter_mut() {
            if c.str.as_bytes()[0] == s.as_bytes()[0] {
                c.insert(&s);
                return
            }
        }
        self.children.push(Node::new(&s))
    }
    
    fn sum(&self) -> i64 {
        self.children.iter().map(|c| c.sum()).sum::<i64>()
    }
}

impl fmt::Display for Tree {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = "*\n";
        let v: Vec<String> = self.children.iter()
            .flat_map(|c| format!("{}", c).split('\n').map(|s1| format!("  {}", s1)).collect::<Vec<String>>())
            .collect();
        write!(f, "{}{}", s, v.join("\n"))
    }
}


//////////////////// process ////////////////////

fn read_input() -> Vec<String> {
    let _N: usize = read();
    let A: Vec<String> = read_vec();
    A
}

fn F(A: Vec<String>) -> i64 {
    let mut tree = Tree::new();
    for s in A.into_iter() {
        tree.insert(s);
    }
    tree.sum()
}

fn main() {
    let A = read_input();
    println!("{}", F(A))
}

AtCoder Beginner Contest 353 D

https://atcoder.jp/contests/abc353/tasks/abc353_d

AtCoderではあまりないですが、和の取り方を逆にすればいい問題ですね。

 \displaystyle \sum_{i=1}^{N-1}{\sum_{j=i+1}^N{f(A_i, A_j)}} = \sum_{j=2}^N{\sum_{i=1}^{j-1}{f(A_i, A_j)}}

// Another Sigma Problem
#![allow(non_snake_case)]

const D: u64 = 998244353;


//////////////////// library ////////////////////

fn read<T: std::str::FromStr>() -> T {
    let mut line = String::new();
    std::io::stdin().read_line(&mut line).ok();
    line.trim().parse().ok().unwrap()
}

fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    read::<String>().split_whitespace()
            .map(|e| e.parse().ok().unwrap()).collect()
}


//////////////////// process ////////////////////

fn read_input() -> Vec<u64> {
    let _N: usize = read();
    let A: Vec<u64> = read_vec();
    A
}

fn mul(mut s: u64, j: usize, a: u64) -> u64 {
    let mut b = a;
    while b > 0 {
        s *= 10;
        b /= 10
    }
    (s + a * (j as u64)) % D
}

fn F(A: Vec<u64>) -> u64 {
    let N = A.len();
    let mut s: u64 = 0;
    let mut s1: u64 = 0;
    for j in 1..N {
        s1 = (s1 + A[j-1]) % D;
        s = (s + mul(s1, j, A[j])) % D
    }
    s
}

fn main() {
    let A = read_input();
    println!("{}", F(A))
}

MojoでProject Euler 31(4)

https://projecteuler.net/problem=31

前回、同じようなコード、

            for i in range(e, self.L-width, width):
                var e1 = self.a.load[width=nelts](i)
                var e2 = self.a.load[width=nelts](i-e)
                self.a.store[width=nelts](i, (e1+e2)%D)

が3つ出てきましたが、次のようにすれば同じコードにできます。ただし、これでもneltsが16だとうまくいきません。一般に書くのは難しそうです。

from math import max
import sys


#################### constatns ####################

# number of elements
alias nelts = simdwidthof[DType.int32]()
alias D: SIMD[DType.int32, 1] = 10**9+7


#################### Polynomial ####################

struct Polynomial:
    var a: DTypePointer[DType.int32]
    var L: Int
    
    fn __init__(inout self, a: DTypePointer[DType.int32], L: Int):
        self.a = a
        self.L = L
    
    fn __del__(owned self):
        print("__del__")
        pass
    
    fn __str__(self) -> String:
        var s = str(self.a[0])
        for i in range(1, self.L):
            s += " " + str(self.a[i])
        return s
    
    fn value(self, i: Int) -> SIMD[DType.int32, 1]:
        return self.a.load(i)
    
    fn divide_each[width: Int](inout self, e: Int):
        for i in range(e, self.L-width, width):
            var e1 = self.a.load[width=width](i)
            var e2 = self.a.load[width=width](i-e)
            self.a.store[width=width](i, (e1+e2)%D)
    
    fn divide(inout self, e: Int):
        fn get_width(w: Int) -> Int:
            var width = nelts
            while w < width:
                width >>= 1
            return width
        
        var width = get_width(e)
        if e >= nelts:
            self.divide_each[nelts](e)
        elif e >= 4:
            self.divide_each[4](e)
        elif e >= 2:
            self.divide_each[2](e)
        
        var first = max(e, e+(self.L-e-width-1)//width*width+width)
        for j in range(first, self.L):
            var e1 = self.a.load(j)
            var e2 = self.a.load(j-e)
            self.a.store(j, (e1+e2)%D)


#################### process ####################

fn collect_coins(N: Int) -> List[Int]:
    var ns = List[Int](1, 2, 5);
    var ps = List[Int]()
    for e in range(19):
        for n in ns:
            var p = n[] * 10**e
            if p > N:
                break
            ps.append(p)
    return ps

# 1/(1-x)
fn initialize(N: Int) -> Polynomial:
    var L = N // nelts + 1
    var ones = SIMD[DType.int32, nelts](1)
    var a = SIMD[DType.int32, nelts](1)
    var p = DTypePointer[DType.int32].alloc(L*nelts)
    for i in range(0, L*nelts, nelts):
        p.store[width=nelts](i, a)
    return Polynomial(p, L*nelts)

fn f(N: Int) -> SIMD[DType.int32, 1]:
    var p = initialize(N)
    var ps = collect_coins(N)
    for i in range(1, ps.size):
        p.divide(ps[i])
    
    return p.value(N)

fn main() raises:
    var args = sys.argv()
    var N = atol(args[1])
    print(f(N))