Solution

Memo

  • 그리디 입문 문제
  • 그리디로 풀린다는 직관을 갖기까지가 어려운 것 같다.
  • 반대로 그리디인걸 알고 풀면 엄청 쉽게쉽게 풀린다.
// https://www.acmicpc.net/problem/1461
// Baekjoon - 1461

use std::{
    cmp,
    io::{self, Read, Write},
};

// -1,  3 (4 5) (6 11)
// (-45 -26 -18) (-9 -4),  (22 40 50)
fn main() {
    let mut stdin = io::stdin().lock();
    let mut stdout = io::stdout().lock();
    let mut input = String::new();
    stdin.read_to_string(&mut input).unwrap();
    let mut lines = input.lines();

    let first_line = lines.next().unwrap();
    let mut parts = first_line.split_whitespace();
    let _n: usize = parts.next().unwrap().parse().unwrap();
    let holdable: usize = parts.next().unwrap().parse().unwrap();

    // 음수와 양수는 다르게 접근해야함
    let mut plus: Vec<i32> = Vec::new();
    let mut minus: Vec<i32> = Vec::new();

    if let Some(line) = lines.next() {
        for num_str in line.split_whitespace() {
            if let Ok(num) = num_str.parse::<i32>() {
                if num >= 0 {
                    plus.push(num);
                } else {
                    minus.push(num.abs());
                }
            }
        }
    }

    // 내림차순
    plus.sort_by(|a, b| b.cmp(a));
    minus.sort_by(|a, b| b.cmp(a));

    let mut result = 0;
    let mut max_dist = 0;

    // 내림차순, 0번원소부터 즉 가장 큰 원소부터 한번에 들 수 있는 값만큼 step_by()
    for i in (0..plus.len()).step_by(holdable) {
        // 가장 긴 거리를 카운트
        if i == 0 {
            max_dist = cmp::max(max_dist, plus[i]);
        }

        result += plus[i] * 2;
    }

    // 위와 동일
    for i in (0..minus.len()).step_by(holdable) {
        if i == 0 {
            max_dist = cmp::max(max_dist, minus[i]);
        }

        result += minus[i] * 2;
    }

    // 가장 긴 거리 한 번을 빼줌, (다놓고 돌아올 필요가 없음)
    result -= max_dist;

    write!(stdout, "{}", result).unwrap();
}