#![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 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, rng.gen_range(0, 26));
			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.9 {
		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.95 {
		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);
	}
}


Measured memory_bytes: 3864