use std::convert::TryInto;
use std::env;

struct Ixs {
    ixs: Vec<usize>,
    max: usize,
}

impl Iterator for Ixs {
    type Item = Vec<usize>;
    fn next(&mut self) -> Option<Self::Item> {
        let mut ixix = self.ixs.len() - 1;
        loop {
            let v = self.ixs[ixix] + 1;
            if v > self.max {
                if ixix == 0 {
                    return None;
                } else {
                    ixix = ixix - 1;
                }
            } else {
                for ixiy in ixix..self.ixs.len() {
                    self.ixs[ixiy] = v;
                }
                return Some(self.ixs.clone());
            }
        }
    }
}

impl Ixs {
    fn new(count: usize, max: usize) -> Self {
        let mut r = Ixs {
            ixs: Vec::new(),
            max: max,
        };
        r.ixs.resize(count, 0);
        r
    }
}

fn find2020(i: &Vec<i64>, n: i64) -> i64 {
    for ixs in Ixs::new(n.try_into().unwrap(), i.len() - 1) {
        if ixs.iter().map(|ix| i[*ix]).sum::<i64>() == 2020 {
            return ixs.iter().map(|ix| i[*ix]).product();
        }
    }
    panic!("Not found!")
}

fn main() {
    let args: Vec<_> = env::args().collect();
    let numbers: Vec<i64> = std::fs::read_to_string(&args[1])
        .unwrap()
        .split_whitespace()
        .map(|l| l.parse().unwrap())
        .collect();
    println!("{}", find2020(&numbers, args[2].parse().unwrap()));
}