use itertools::{Itertools, enumerate, izip}; use proconio::{input, marker::Usize1}; fn main() { input! { q: usize, } let output = (0..q) .map(|_| { let (i, j) = solve(); format!("{} {}", i + 1, j + 1) }) .join("\n"); println!("{output}"); } fn solve() -> (usize, usize) { input! { (n, m, k, p): (usize, usize, usize, usize), tt: [u64; n], cc: [Usize1; n], bb: [u64; m], dd: [Usize1; m], ss: [u64; k], } let tops = enumerate(izip!(&tt, &cc)) .map(|(i, (&t, &c))| Suit::new(i, t, c)) .collect_vec(); let bottoms = enumerate(izip!(&bb, &dd)) .map(|(i, (&b, &d))| Suit::new(i, b, d)) .sorted_unstable_by_key(|suit| (suit.cost, suit.color)) .collect_vec(); let mut bottom_by_color = vec![vec![]; k]; for &bottom in &bottoms { bottom_by_color[bottom.color].push(bottom); } let is_ok = |max_cost: u64| { let num_combs = tops .iter() .map(|top| { if top.cost > max_cost { return 0; } let max_rem_cost = max_cost - top.cost; let whole_upper = bottoms.partition_point(|bottom| bottom.cost <= max_rem_cost); let upper_without_discount = bottom_by_color[top.color] .partition_point(|bottom| bottom.cost <= max_rem_cost); let upper_with_discount = bottom_by_color[top.color] .partition_point(|bottom| bottom.cost <= max_rem_cost + ss[top.color]); whole_upper + upper_with_discount - upper_without_discount }) .sum::(); num_combs >= p }; let mut ok = 2 * 10_u64.pow(9); let mut ng = 0_u64; while ok.abs_diff(ng) > 1 { let mid = (ok + ng) / 2; if is_ok(mid) { ok = mid; } else { ng = mid; } } for (top_id, top) in enumerate(&tops) { if top.cost > ok { continue; } let rem_cost = ok - top.cost; let lower = bottoms.partition_point(|bottom| bottom.cost < rem_cost); let upper = bottoms.partition_point(|bottom| bottom.cost <= rem_cost); if lower < upper { if bottoms[lower].color != top.color { return (top_id, bottoms[lower].id); } if bottoms[upper - 1].color != top.color { return (top_id, bottoms[upper - 1].id); } } let bottoms = &bottom_by_color[top.color]; let lower = bottoms.partition_point(|bottom| bottom.cost < rem_cost + ss[top.color]); let upper = bottoms.partition_point(|bottom| bottom.cost <= rem_cost + ss[top.color]); if lower < upper { return (top_id, bottoms[lower].id); } } (100, 100) } #[derive(Debug, Clone, Copy)] struct Suit { id: usize, cost: u64, color: usize, } impl Suit { fn new(id: usize, cost: u64, color: usize) -> Self { Self { id, cost, color } } }