#![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,
	prev: Vec<Vec<usize>>,
	next: Vec<Vec<usize>>,
}

impl State {
	fn new(input: &Input, out: Vec<usize>) -> State {
		let mut prev = mat![!0; 26; input.D + 1];
		let mut next = mat![input.D; 26; input.D + 1];
		for d in 0..input.D {
			for i in 0..26 {
				prev[i][d + 1] = prev[i][d];
			}
			prev[out[d]][d + 1] = d;
		}
		for d in (0..input.D).rev() {
			for i in 0..26 {
				next[i][d] = next[i][d + 1];
			}
			next[out[d]][d] = d;
		}
		let score = compute_score(&input, &out);
		State { out, score, prev, next }
	}
	fn try_shift(&self, input: &Input, d: usize, d2: usize) -> i64 {
		let i = self.out[d];
		let prev = self.prev[i][d];
		let next = self.next[i][d + 1];
		let before = input.s[d][i] - input.c[i] * (cost(prev, d) + cost(d, next));
		let after = if d2 == !0 {
			-input.c[i] * cost(prev, next)
		} else {
			input.s[d2][i] - input.c[i] * (cost(prev, d2) + cost(d2, next))
		};
		after - before
	}
	fn try_insert(&self, input: &Input, d: usize, i: usize) -> i64 {
		let prev = self.prev[i][d];
		let next = self.next[i][d + 1];
		let before = -input.c[i] * cost(prev, next);
		let after = input.s[d][i] - input.c[i] * (cost(prev, d) + cost(d, next));
		after - before
	}
	fn update(&mut self, i: usize, prev: usize, d2: usize, next: usize) {
		for d in prev+1..=d2 {
			self.prev[i][d] = prev;
			self.next[i][d] = d2;
		}
		for d in d2+1..=next {
			self.prev[i][d] = d2;
			self.next[i][d] = next;
		}
	}
	fn swap(&mut self, d1: usize, d2: usize) {
		let (i1, i2) = (self.out[d1], self.out[d2]);
		let (prev1, next1) = (self.prev[i1][d1], self.next[i1][d1 + 1]);
		let (prev2, next2) = (self.prev[i2][d2], self.next[i2][d2 + 1]);
		self.out.swap(d1, d2);
		self.update(i1, prev1, d2, next1);
		self.update(i2, prev2, d1, next2);
	}
	fn change(&mut self, d: usize, i: usize) {
		let j = self.out[d];
		let (prev1, next1) = (self.prev[i][d], self.next[i][d + 1]);
		let (prev2, next2) = (self.prev[j][d], self.next[j][d + 1]);
		self.out[d] = i;
		self.update(i, prev1, d, next1);
		for d in prev2+1..=next2 {
			self.prev[j][d] = prev2;
			self.next[j][d] = next2;
		}
	}
}

fn solve(input: &Input) -> Vec<usize> {
	const T0: f64 = 2e3;
	const T1: f64 = 4e2;
	const TL: f64 = 1.9;
	let mut rng = rand_pcg::Pcg64Mcg::new(890482);
	let rlog = (0..0x10000).map(|_| rng.gen::<f64>().ln()).collect::<Vec<_>>();
	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 = T0;
	let mut best = state.score;
	let mut best_out = state.out.clone();
	loop {
		cnt += 1;
		if cnt % 1000 == 0 {
			let t = (get_time() - stime) / TL;
			if t >= 1.0 {
				break;
			}
			T = T0.powf(1.0 - t) * T1.powf(t);
			if t > 0.5 {
				if improve_cycle(input, &mut state, &mut rng) {
					if best.setmax(state.score) {
						eprintln!("time: {:.3}, T: {:.0}, score: {} by cycle", get_time(), T, best);
						best_out = state.out.clone();
					}
				}
			}
		}
		if rng.gen_bool(0.5) {
			let d = rng.gen_range(0, input.D);
			let i = rng.gen_range(0, 26);
			if state.out[d] == i {
				continue;
			}
			let diff = state.try_shift(input, d, !0) + state.try_insert(input, d, i);
			if diff as f64 > T * rlog[cnt & 0xffff] {
				state.change(d, i);
				state.score += diff;
			}
		} else {
			let d1 = rng.gen_range(0, input.D);
			let prev = state.prev[state.out[d1]][d1];
			let next = state.next[state.out[d1]][d1 + 1];
			let d2 = rng.gen_range(prev + 1, next);
			if d1 == d2 {
				continue;
			}
			let prev2 = state.prev[state.out[d2]][d2];
			let next2 = state.next[state.out[d2]][d2 + 1];
			if !(prev2 + 1 <= d1 && d1 < next2) {
				continue;
			}
			let diff = state.try_shift(&input, d1, d2) + state.try_shift(&input, d2, d1);
			if diff as f64 > T * rlog[cnt & 0xffff] {
				state.swap(d1, d2);
				state.score += diff;
			}
		}
		if best.setmax(state.score) {
			eprintln!("time: {:.3}, T: {:.0}, score: {}", get_time(), T, best);
			best_out = state.out.clone();
		}
	}
	eprintln!("Iter = {}", cnt);
	state = State::new(input, best_out);
	while get_time() < 1.95 {
		improve_cycle(input, &mut state, &mut rng);
	}
	state.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, state: &mut State, rng: &mut rand_pcg::Pcg64Mcg) -> bool {
	let ds = {
		let mut del = vec![false; input.D];
		let mut tmp = (0..input.D).collect::<Vec<_>>();
		tmp.shuffle(rng);
		let mut checked = vec![false; input.D];
		for c in tmp {
			if checked[c] {
				continue;
			}
			for a in 0..20 {
				for &d in &[c - a, c + a] {
					if d >= input.D {
						continue;
					}
					checked[d] = true;
					let i = state.out[d];
					if !(del[d] || state.prev[i][d] != !0 && del[state.prev[i][d]] || state.next[i][d + 1] < input.D && del[state.next[i][d + 1]]) {
						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 = state.out[d];
			g[u].push((n + 26, -state.try_shift(input, d, !0)));
			for d2 in state.prev[i][d]+1..state.next[i][d + 1] {
				let v = vid[d2];
				if v == !0 || d == d2 {
					continue;
				}
				g[u].push((v, -state.try_shift(input, d, d2)));
			}
			for j in 0..26 {
				if i == j || state.prev[j][d] != !0 && vid[state.prev[j][d]] != !0 || state.next[j][d + 1] < input.D && vid[state.next[j][d + 1]] != !0 {
					continue;
				}
				g[n + j].push((u, -state.try_insert(input, d, j)));
			}
		}
		for i in 0..26 {
			g[n + 26].push((n + i, 0));
		}
	}
	if let Some(cycle) = find_negative_cycle(&g) {
		let old = compute_score(&input, &state.out);
		let mut out2 = state.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()]]] = state.out[ds[cycle[i]]];
			}
		}
		let new_score = compute_score(&input, &out2);
		*state = State::new(input, out2);
		assert!(old < new_score);
		true
	} else {
		false
	}
}

fn run() {
	get_time();
	let input = read_input();
	let out = solve(&input);
	eprintln!("Time = {:.3}", get_time());
	eprintln!("Score = {}", compute_score(&input, &out));
	for i in 0..input.D {
		println!("{}", out[i] + 1);
	}
}


Measured memory_bytes: 4060