| Task: | Uolevin kalansaalis |
| Sender: | EmuBird |
| Submission time: | 2023-11-02 18:45:03 +0200 |
| Language: | Rust |
| Status: | READY |
| Result: | 100 |
| group | verdict | score |
|---|---|---|
| #1 | ACCEPTED | 37 |
| #2 | ACCEPTED | 63 |
| test | verdict | time | group | |
|---|---|---|---|---|
| #1 | ACCEPTED | 0.00 s | 1, 2 | details |
| #2 | ACCEPTED | 0.00 s | 1, 2 | details |
| #3 | ACCEPTED | 0.00 s | 1, 2 | details |
| #4 | ACCEPTED | 0.00 s | 1, 2 | details |
| #5 | ACCEPTED | 0.00 s | 1, 2 | details |
| #6 | ACCEPTED | 0.00 s | 1, 2 | details |
| #7 | ACCEPTED | 0.00 s | 1, 2 | details |
| #8 | ACCEPTED | 0.00 s | 1, 2 | details |
| #9 | ACCEPTED | 0.00 s | 1, 2 | details |
| #10 | ACCEPTED | 0.00 s | 1, 2 | details |
| #11 | ACCEPTED | 0.00 s | 1, 2 | details |
| #12 | ACCEPTED | 0.00 s | 1, 2 | details |
| #13 | ACCEPTED | 0.00 s | 1, 2 | details |
| #14 | ACCEPTED | 0.00 s | 1, 2 | details |
| #15 | ACCEPTED | 0.00 s | 1, 2 | details |
| #16 | ACCEPTED | 0.53 s | 2 | details |
| #17 | ACCEPTED | 0.53 s | 2 | details |
| #18 | ACCEPTED | 0.55 s | 2 | details |
| #19 | ACCEPTED | 0.52 s | 2 | details |
| #20 | ACCEPTED | 0.53 s | 2 | details |
| #21 | ACCEPTED | 0.52 s | 2 | details |
| #22 | ACCEPTED | 0.52 s | 2 | details |
| #23 | ACCEPTED | 0.52 s | 2 | details |
| #24 | ACCEPTED | 0.53 s | 2 | details |
Code
use std::fmt::{Debug, Display, Formatter};
use std::{cmp, io};
fn main() {
let stdin = io::stdin();
let (height, width, k) = {
let mut input: String = String::new();
stdin.read_line(&mut input).unwrap();
let input = input.trim_end();
let mut values = input.split_whitespace().map(|value| {
value.parse::<usize>().unwrap()
});
(values.next().unwrap(), values.next().unwrap(), values.next().unwrap())
};
let (net, total_price_sum) = {
// A vector of contents of the net. Indexed by net[coordinate.y][coordinate.x] where coordinate is a Coordinate.
let mut net: Vec<Vec<i8>> = vec![vec![0; width]; height];
// What the total sum would be without cutting any triangle
let mut total_price_sum: i32 = 0;
for _ in 0..k {
let mut input: String = String::new();
stdin.read_line(&mut input).unwrap();
let input = input.trim_end();
// Parse coordinate
let mut values = input.split_whitespace();
let coord = Coordinate {
y: values.next().unwrap().parse::<usize>().unwrap() - 1,
x: values.next().unwrap().parse::<usize>().unwrap() - 1
};
let content: i8 = match values.next().unwrap() {
"H" | "h" => { 1 } // Hauki
"K" | "k" => { -10 } // Katkarapu
text => {
// Accept integer values for debugging
text.parse().unwrap_or_else(|_| panic!("Unknown content type! H or K?"))
}
};
total_price_sum += content as i32;
net[coord.y][coord.x] = content;
}
(net, total_price_sum)
};
// In the worst case, the net is full of 1s, so the smallest triangle would consist of one cell, the sum of which would be 1.
let mut optimal_solution: i32 = 1;
let optimal_solution_upwards: i32 = find_optimal_triangle(&net, height, width, false, optimal_solution);
let optimal_solution_downwards: i32 = {
let flipped_net: Vec<Vec<i8>> = net
.iter()
.rev()
.map(|row|
row
.iter()
.map(|v| *v)
.collect()
)
.collect();
let is_shifted = height % 2 == 0; // Flipping the net causes the coordinate system to be shifted if the height is even.
find_optimal_triangle(&flipped_net, height, width, is_shifted, optimal_solution)
};
optimal_solution = cmp::min(optimal_solution_upwards, optimal_solution_downwards);
println!("{}", total_price_sum - optimal_solution);
}
/// Tries to find the smallest possible amount of profit possible (in other words, the smallest sum of the cells) within an upward-pointing triangle.
fn find_optimal_triangle(net: &Vec<Vec<i8>>, height: usize, width: usize, is_shifted: bool, mut optimal_solution: i32) -> i32 {
/// Generates CellData for a cell that cannot continue any further
fn ending_cell(content: i32) -> CellData {
let v: Vec<i32> = vec![content];
CellData {
left_partial_table: v.clone(),
complete_table: v,
}
}
// Calculate bottom row manually
let mut last_row = {
let mut last_row: Vec<CellData> = Vec::with_capacity(width);
let bottom_net_row = &net[height - 1];
for i in 0..width {
let content = bottom_net_row[i] as i32;
if content < optimal_solution {
optimal_solution = content;
}
last_row.push(ending_cell(content));
}
last_row
};
// Calculate for the rest of the rows.
for y in (0..(height - 1)).rev() {
let net_row = &net[y];
let mut this_row = Vec::with_capacity(width);
for x in 0..width {
let coordinate = Coordinate { x, y };
let content = *&net_row[x] as i32;
let (left, right) = coordinate.get_coordinates_below(width, height, is_shifted);
if left.is_none() || right.is_none() {
// A triangle cannot continue further.
if content < optimal_solution {
optimal_solution = content;
}
this_row.push(ending_cell(content));
} else {
// A triangle can continue further.
// Get CellData for both cells below.
let left = &last_row[left.unwrap().x];
let right = &last_row[right.unwrap().x];
let max_depth = cmp::min(left.left_partial_table.len(), right.complete_table.len()) + 1;
let mut left_partial_table = Vec::with_capacity(max_depth);
let mut complete_table = Vec::with_capacity(max_depth);
for t in 0..max_depth {
let left_partial = if t > 0 { left.left_partial_table[t - 1] } else { 0 } + content;
left_partial_table.push(left_partial);
let complete = if t > 0 { right.complete_table[t - 1] } else { 0 } + left_partial;
complete_table.push(complete);
if complete < optimal_solution {
optimal_solution = complete;
}
}
this_row.push(CellData {
left_partial_table,
complete_table,
});
}
}
last_row = this_row;
}
optimal_solution
}
/// Represents a coordinate.
/// In this program the coordinate system is as follows:
/// - X axis is horizontally from left to right
/// - Y axis is vertically from TOP TO BOTTOM
/// - Coordinates start from 0
struct Coordinate {
x: usize,
y: usize
}
impl Debug for Coordinate {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(&*format!("({}, {}; x={}, y={})", &self.y + 1, &self.x + 1, &self.x, &self.y))
}
}
impl Display for Coordinate {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(&*format!("({}, {})", &self.y + 1, &self.x + 1))
}
}
impl Coordinate {
/// Gets the coordinates for the cells below this coordinate. Returns as (left, right).
/// The coordinate system is interpreted as follows:
/// - If`!is_shifted`, the top left cell only has one cell below it to the right. Top right cell has cells below it on both sides.
/// - If `is_shifted`, the top left cell also has a cell below it to the left, but the rightmost cell on the top row will not have a cell underneath it to the right.
fn get_coordinates_below(&self, width: usize, height: usize, is_shifted: bool) -> (Option<Coordinate>, Option<Coordinate>) {
assert!(self.x < width, "X is out of bounds");
assert!(self.y < height, "Y is out of bounds");
// If there is no row below
if self.y >= height - 1 {
return (None, None);
}
// Whether the leftmost cell of this row is located more to the left compared to adjacent rows.
let starts_toward_left = self.y % 2 == if is_shifted { 1 } else { 0 };
// Left
let left: Option<usize> = match starts_toward_left {
true => {
if self.x > 0 {
Some(self.x - 1)
} else {
None
}
}
false => {
Some(self.x)
}
};
// Right
let right: Option<usize> = match starts_toward_left {
true => {
Some(self.x)
}
false => {
if self.x < width - 1 {
Some(self.x + 1)
} else {
None
}
}
};
fn to_coordinate(x: Option<usize>, y: usize) -> Option<Coordinate> {
x.and_then(|x| Some(Coordinate { x, y }))
}
return (to_coordinate(left, self.y + 1), to_coordinate(right, self.y + 1))
}
}
struct CellData {
/// If this was the tip of an upward-pointing triangle with the depth of t, the sum of its cells following its left edge would be `left_partial_table[t]`.
left_partial_table: Vec<i32>,
/// If this was the tip of an upward-pointing triangle with the depth of t, the sum of its cells would be `complete_table[t]`.
complete_table: Vec<i32>
}
Test details
Test 1
Group: 1, 2
Verdict: ACCEPTED
| input |
|---|
| 5 6 13 1 1 K 5 1 K 2 2 H 4 2 H ... |
| correct output |
|---|
| -16 |
| user output |
|---|
| -16 |
Test 2
Group: 1, 2
Verdict: ACCEPTED
| input |
|---|
| 5 6 7 1 5 K 4 6 K 2 4 H 2 5 H ... |
| correct output |
|---|
| 0 |
| user output |
|---|
| 0 |
Test 3
Group: 1, 2
Verdict: ACCEPTED
| input |
|---|
| 5 6 7 5 5 K 2 6 K 2 4 H 2 5 H ... |
| correct output |
|---|
| 0 |
| user output |
|---|
| 0 |
Test 4
Group: 1, 2
Verdict: ACCEPTED
| input |
|---|
| 10 10 51 3 3 H 6 3 H 9 5 H 5 10 H ... |
| correct output |
|---|
| 50 |
| user output |
|---|
| 50 |
Test 5
Group: 1, 2
Verdict: ACCEPTED
| input |
|---|
| 10 10 52 3 5 H 3 1 H 9 6 H 2 8 H ... |
| correct output |
|---|
| 40 |
| user output |
|---|
| 40 |
Test 6
Group: 1, 2
Verdict: ACCEPTED
| input |
|---|
| 10 10 60 6 10 H 2 8 H 5 8 H 8 10 H ... |
| correct output |
|---|
| -15 |
| user output |
|---|
| -15 |
Test 7
Group: 1, 2
Verdict: ACCEPTED
| input |
|---|
| 10 10 60 4 7 H 7 4 H 4 10 H 3 6 H ... |
| correct output |
|---|
| 60 |
| user output |
|---|
| 60 |
Test 8
Group: 1, 2
Verdict: ACCEPTED
| input |
|---|
| 10 10 40 9 9 H 5 10 H 5 6 H 4 9 H ... |
| correct output |
|---|
| 2 |
| user output |
|---|
| 2 |
Test 9
Group: 1, 2
Verdict: ACCEPTED
| input |
|---|
| 1 1 0 |
| correct output |
|---|
| 0 |
| user output |
|---|
| 0 |
Test 10
Group: 1, 2
Verdict: ACCEPTED
| input |
|---|
| 1 1 1 1 1 K |
| correct output |
|---|
| 0 |
| user output |
|---|
| 0 |
Test 11
Group: 1, 2
Verdict: ACCEPTED
| input |
|---|
| 1 1 1 1 1 H |
| correct output |
|---|
| 0 |
| user output |
|---|
| 0 |
Test 12
Group: 1, 2
Verdict: ACCEPTED
| input |
|---|
| 10 5 32 10 3 H 4 4 H 3 3 H 5 4 H ... |
| correct output |
|---|
| 20 |
| user output |
|---|
| 20 |
Test 13
Group: 1, 2
Verdict: ACCEPTED
| input |
|---|
| 5 10 32 5 9 H 2 4 H 2 9 H 2 5 H ... |
| correct output |
|---|
| 28 |
| user output |
|---|
| 28 |
Test 14
Group: 1, 2
Verdict: ACCEPTED
| input |
|---|
| 10 10 100 2 9 H 5 4 H 5 9 K 6 1 K ... |
| correct output |
|---|
| -439 |
| user output |
|---|
| -439 |
Test 15
Group: 1, 2
Verdict: ACCEPTED
| input |
|---|
| 10 10 100 8 9 H 5 10 H 5 4 H 3 9 H ... |
| correct output |
|---|
| 88 |
| user output |
|---|
| 88 |
Test 16
Group: 2
Verdict: ACCEPTED
| input |
|---|
| 500 500 125000 125 261 K 84 78 K 11 200 K 481 246 K ... |
| correct output |
|---|
| -624270 |
| user output |
|---|
| -624270 |
Test 17
Group: 2
Verdict: ACCEPTED
| input |
|---|
| 500 500 125100 16 61 H 37 62 H 459 125 H 318 476 H ... |
| correct output |
|---|
| 124020 |
| user output |
|---|
| 124020 |
Test 18
Group: 2
Verdict: ACCEPTED
| input |
|---|
| 500 500 249999 22 214 H 356 145 H 341 29 H 393 262 H ... |
| correct output |
|---|
| 249999 |
| user output |
|---|
| 249999 |
Test 19
Group: 2
Verdict: ACCEPTED
| input |
|---|
| 500 500 32000 30 81 H 315 34 H 78 112 H 367 166 H ... |
| correct output |
|---|
| 10126 |
| user output |
|---|
| 10126 |
Test 20
Group: 2
Verdict: ACCEPTED
| input |
|---|
| 500 500 126745 164 390 H 126 331 H 164 126 H 55 92 H ... |
| correct output |
|---|
| -104692 |
| user output |
|---|
| -104692 |
Test 21
Group: 2
Verdict: ACCEPTED
| input |
|---|
| 500 500 71200 106 191 H 314 189 H 482 485 H 344 401 H ... |
| correct output |
|---|
| -335853 |
| user output |
|---|
| -335853 |
Test 22
Group: 2
Verdict: ACCEPTED
| input |
|---|
| 500 500 67772 421 277 H 428 470 H 169 142 H 256 345 H ... |
| correct output |
|---|
| -208567 |
| user output |
|---|
| -208567 |
Test 23
Group: 2
Verdict: ACCEPTED
| input |
|---|
| 500 500 27434 366 481 H 38 22 H 126 107 H 135 169 H ... |
| correct output |
|---|
| -57100 |
| user output |
|---|
| -57100 |
Test 24
Group: 2
Verdict: ACCEPTED
| input |
|---|
| 500 500 93982 183 13 H 463 230 H 264 351 H 399 290 H ... |
| correct output |
|---|
| -52800 |
| user output |
|---|
| -52800 |
