//  [rust]
#![allow(non_snake_case, unused)]
use rand::prelude::*;
pub trait SetMinMax {
    fn setmin(&mut self, v: Self) -> bool;
    fn setmax(&mut self, v: Self) -> bool;
}
impl<T> SetMinMax for T
where
    T: PartialOrd,
{
    fn setmin(&mut self, v: T) -> bool {
        *self > v && {
            *self = v;
            true
        }
    }
    fn setmax(&mut self, v: T) -> bool {
        *self < v && {
            *self = v;
            true
        }
    }
}
#[macro_export]
#[allow(unused)]
macro_rules! mat {
	($($e:expr),*) => { Vec::from(vec![$($e),*]) };
	($($e:expr,)*) => { Vec::from(vec![$($e),*]) };
	($e:expr; $d:expr) => { Vec::from(vec![$e; $d]) };
	($e:expr; $d:expr $(; $ds:expr)+) => { Vec::from(vec![mat![$e $(; $ds)*]; $d]) };
}
pub fn readln() -> String {
    let mut line = String::new();
    ::std::io::stdin()
        .read_line(&mut line)
        .unwrap_or_else(|e| panic!("{}", e));
    line
}
macro_rules! read {
	($($t:tt),*; $n:expr) => {{
		let stdin = ::std::io::stdin();
		let ret = ::std::io::BufRead::lines(stdin.lock()).take($n).map(|line| {
			let line = line.unwrap();
			let mut it = line.split_whitespace();
			_read!(it; $($t),*)
		}).collect::<Vec<_>>();
		ret
	}};
	($($t:tt),*) => {{
		let line = readln();
		let mut it = line.split_whitespace();
		_read!(it; $($t),*)
	}};
}
macro_rules! _read {
	($it:ident; [char]) => {
		_read!($it; String).chars().collect::<Vec<_>>()
	};
	($it:ident; [u8]) => {
		Vec::from(_read!($it; String).into_bytes())
	};
	($it:ident; usize1) => {
		$it.next().unwrap_or_else(|| panic!("input mismatch")).parse::<usize>().unwrap_or_else(|e| panic!("{}", e)) - 1
	};
	($it:ident; [usize1]) => {
		$it.map(|s| s.parse::<usize>().unwrap_or_else(|e| panic!("{}", e)) - 1).collect::<Vec<_>>()
	};
	($it:ident; [$t:ty]) => {
		$it.map(|s| s.parse::<$t>().unwrap_or_else(|e| panic!("{}", e))).collect::<Vec<_>>()
	};
	($it:ident; $t:ty) => {
		$it.next().unwrap_or_else(|| panic!("input mismatch")).parse::<$t>().unwrap_or_else(|e| panic!("{}", e))
	};
	($it:ident; $($t:tt),+) => {
		($(_read!($it; $t)),*)
	};
}
pub fn main() {
    let _ = ::std::thread::Builder::new()
        .name("run".to_string())
        .stack_size(32 * 1024 * 1024)
        .spawn(run)
        .unwrap()
        .join();
}
pub fn get_time() -> f64 {
    static mut STIME: f64 = -1.0;
    let t = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .unwrap();
    let ms = t.as_secs() as f64 + t.subsec_nanos() as f64 * 1e-9;
    unsafe {
        if STIME < 0.0 {
            STIME = ms;
        }
        ms - STIME
    }
}
#[derive(Clone, Debug)]
pub struct Input {
    pub D: usize,
    pub s: Vec<Vec<i64>>,
    pub c: Vec<i64>,
}
fn read_input() -> Input {
    let D = read!(usize);
    let c = read!([i64]);
    let s = read!([i64]; D);
    Input { D, s, c }
}
pub fn compute_score(input: &Input, out: &Vec<usize>) -> i64 {
    let mut score = 0;
    let mut last = vec![0; 26];
    for d in 0..out.len() {
        last[out[d]] = d + 1;
        for i in 0..26 {
            score -= (d + 1 - last[i]) as i64 * input.c[i];
        }
        score += input.s[d][out[d]];
    }
    score
}
fn cost(a: usize, b: usize) -> i64 {
    let d = b - a;
    (d * (d - 1) / 2) as i64
}
struct State {
    out: Vec<usize>,
    score: i64,
    ds: Vec<Vec<usize>>,
}
impl State {
    fn new(input: &Input, out: Vec<usize>) -> State {
        let mut ds = vec![vec![]; 26];
        for d in 0..input.D {
            ds[out[d]].push(d + 1);
        }
        let score = compute_score(&input, &out);
        State { out, score, ds }
    }
    fn change(&mut self, input: &Input, d: usize, new_i: usize) {
        let old_i = self.out[d];
        let p = self.ds[old_i].iter().position(|a| *a == d + 1).unwrap();
        let prev = self.ds[old_i].get(p - 1).cloned().unwrap_or(0);
        let next = self.ds[old_i].get(p + 1).cloned().unwrap_or(input.D + 1);
        self.ds[old_i].remove(p);
        self.score += (cost(prev, d + 1) + cost(d + 1, next) - cost(prev, next)) * input.c[old_i];
        let p = self.ds[new_i]
            .iter()
            .position(|a| *a > d + 1)
            .unwrap_or(self.ds[new_i].len());
        let prev = self.ds[new_i].get(p - 1).cloned().unwrap_or(0);
        let next = self.ds[new_i].get(p).cloned().unwrap_or(input.D + 1);
        self.ds[new_i].insert(p, d + 1);
        self.score -= (cost(prev, d + 1) + cost(d + 1, next) - cost(prev, next)) * input.c[new_i];
        self.score += input.s[d][new_i] - input.s[d][old_i];
        self.out[d] = new_i;
    }
}
fn solve(input: &Input) -> Vec<usize> {
    const TS: f64 = 2e3;
    const TE: f64 = 6e2;
    const TL: f64 = 1.5;
    let mut assign = vec![0; 26];
    for i in 0..26 {
        assign[i] = input.c[i] as usize + 10;
    }
    let mut assigned = vec![0; assign.iter().sum::<usize>()];
    let mut cur_pointer = 0;
    for i in 0..26 {
        for _ in 0..assign[i] {
            assigned[cur_pointer] = i;
            cur_pointer += 1;
        }
    }
    let mut rng = rand_pcg::Pcg64Mcg::new(890482);
    let mut state = State::new(input, (0..input.D).map(|_| rng.gen_range(0, 26)).collect());
    let stime = get_time();
    let mut cnt = 0;
    let mut T = TS;
    let mut best = state.score;
    let mut best_out = state.out.clone();
    loop {
        cnt += 1;
        if cnt % 100 == 0 {
            let t = (get_time() - stime) / TL;
            if t >= 1.0 {
                break;
            }
            T = TS.powf(1.0 - t) * TE.powf(t);
        }
        let old_score = state.score;
        if rng.gen_bool(0.5) {
            let d = rng.gen_range(0, input.D);
            let old = state.out[d];
            state.change(input, d, assigned[rng.gen_range(0, assigned.len())]);
            if old_score > state.score
                && !rng.gen_bool(f64::exp((state.score - old_score) as f64 / T))
            {
                state.change(input, d, old);
            }
        } else {
            let d1 = rng.gen_range(0, input.D - 1);
            let d2 = rng.gen_range(d1 + 1, (d1 + 16).min(input.D));
            let (a, b) = (state.out[d1], state.out[d2]);
            state.change(input, d1, b);
            state.change(input, d2, a);
            if old_score > state.score
                && !rng.gen_bool(f64::exp((state.score - old_score) as f64 / T))
            {
                state.change(input, d1, a);
                state.change(input, d2, b);
            }
        }
        if best.setmax(state.score) {
            eprintln!("time: {:.3}, T: {:.0}, score: {}", get_time(), T, best);
            best_out = state.out.clone();
        }
    }
    eprintln!("Iter = {}", cnt);
    best_out
}
fn get_cycle(prev: Vec<usize>, mut v: usize) -> Vec<usize> {
    let mut used = vec![!0; prev.len()];
    let mut cs = vec![];
    loop {
        if used[v] != !0 {
            return cs[used[v]..].iter().rev().cloned().collect();
        }
        used[v] = cs.len();
        cs.push(v);
        v = prev[v];
    }
}
fn find_negative_cycle(g: &Vec<Vec<(usize, i64)>>) -> Option<Vec<usize>> {
    let n = g.len();
    let mut dist = vec![0; n];
    let mut prev = vec![!0; n];
    let mut que = std::collections::VecDeque::new();
    let mut active = vec![true; n];
    let mut len = vec![0; n];
    for u in 0..n {
        que.push_back(u);
    }
    while let Some(u) = que.pop_front() {
        active[u] = false;
        for &(v, d) in &g[u] {
            if dist[v] > dist[u] + d {
                dist[v] = dist[u] + d;
                prev[v] = u;
                if !active[v] {
                    active[v] = true;
                    que.push_back(v);
                }
                len[v] = len[u] + 1;
                if len[v] >= n {
                    return Some(get_cycle(prev, v));
                }
            }
        }
    }
    None
}
fn improve_cycle(input: &Input, out: &mut Vec<usize>) {
    let mut rng = rand_pcg::Pcg64Mcg::new(890482);
    let mut cnt = 0;
    while get_time() < 1.991 {
        cnt += 1;
        let mut idx = vec![!0usize; input.D];
        let mut ps = vec![vec![!0]; 26];
        for d in 0..input.D {
            idx[d] = ps[out[d]].len();
            ps[out[d]].push(d);
        }
        for i in 0..26 {
            ps[i].push(input.D);
        }
        let ds = {
            let mut del = vec![false; input.D];
            let mut tmp = (0..input.D).collect::<Vec<_>>();
            tmp.shuffle(&mut rng);
            for c in tmp {
                for a in 0..20 {
                    for &d in &[c - a, c + a] {
                        if d >= input.D
                            || del[d]
                            || idx[d] > 1 && del[ps[out[d]][idx[d] - 1]]
                            || idx[d] < ps[out[d]].len() - 2 && del[ps[out[d]][idx[d] + 1]]
                        {
                            continue;
                        }
                        del[d] = true;
                    }
                }
            }
            (0..input.D).filter(|&d| del[d]).collect::<Vec<_>>()
        };
        let mut vid = vec![!0; input.D];
        for i in 0..ds.len() {
            vid[ds[i]] = i;
        }
        let n = ds.len();
        let mut g = vec![vec![]; n + 27];
        for u in 0..n {
            let d = ds[u];
            let i = out[d];
            let prev = ps[i][idx[d] - 1];
            let next = ps[i][idx[d] + 1];
            let delta = -input.s[d][i] + input.c[i] * (cost(prev, d) + cost(d, next));
            g[u].push((n + 26, -delta + input.c[i] * cost(prev, next)));
            for d2 in prev + 1..next {
                let v = vid[d2];
                if v == !0 || d == d2 {
                    continue;
                }
                let delta2 =
                    delta + input.s[d2][i] - input.c[i] * (cost(prev, d2) + cost(d2, next));
                g[u].push((v, -delta2));
            }
        }
        for i in 0..26 {
            for j in 0..ps[i].len() - 1 {
                let prev = ps[i][j];
                let next = ps[i][j + 1];
                if j > 0 && vid[prev] != !0 || j + 1 < ps[i].len() - 1 && vid[next] != !0 {
                    continue;
                }
                for d in ps[i][j] + 1..ps[i][j + 1] {
                    let u = vid[d];
                    if u != !0 {
                        let delta = input.s[d][i]
                            - input.c[i] * (cost(prev, d) + cost(d, next) - cost(prev, next));
                        g[n + i].push((u, -delta));
                    }
                }
            }
            g[n + 26].push((n + i, 0));
        }
        if let Some(cycle) = find_negative_cycle(&g) {
            let old = compute_score(&input, &out);
            let mut out2 = out.clone();
            for i in 0..cycle.len() {
                if cycle[(i + 1) % cycle.len()] >= n {
                } else if cycle[i] >= n {
                    out2[ds[cycle[(i + 1) % cycle.len()]]] = cycle[i] - n;
                } else {
                    out2[ds[cycle[(i + 1) % cycle.len()]]] = out[ds[cycle[i]]];
                }
            }
            let new_score = compute_score(&input, &out2);
            *out = out2;
            dbg!(cnt, new_score);
            assert!(old < new_score);
        }
    }
    dbg!(cnt);
}
fn improve_ls(input: &Input, out: &mut Vec<usize>) {
    let mut state = State::new(input, out.clone());
    let mut score = state.score;
    while get_time() < 1.991 {
        let mut ok = false;
        for d in 0..input.D {
            for i in 0..26 {
                let old = state.out[d];
                state.change(input, d, i);
                if score.setmax(state.score) {
                    ok = true;
                } else {
                    state.change(input, d, old);
                }
            }
            for d2 in d + 1..input.D {
                if out[d] == out[d2] {
                    break;
                }
                let (a, b) = (state.out[d], state.out[d2]);
                state.change(input, d, b);
                state.change(input, d2, a);
                if score.setmax(state.score) {
                    ok = true;
                } else {
                    state.change(input, d, a);
                    state.change(input, d2, b);
                }
            }
        }
        if !ok {
            break;
        }
    }
    *out = state.out;
}
fn run() {
    get_time();
    let input = read_input();
    let mut out = solve(&input);
    improve_cycle(&input, &mut out);
    dbg!(compute_score(&input, &out));
    improve_ls(&input, &mut out);
    eprintln!("Time = {:.3}", get_time());
    eprintln!("Score = {}", compute_score(&input, &out));
    for i in 0..input.D {
        println!("{}", out[i] + 1);
    }
}