| Task: | Robotti | 
| Sender: | wolruso | 
| Submission time: | 2024-11-04 22:19:28 +0200 | 
| Language: | Rust (2021) | 
| Status: | READY | 
| Result: | 100 | 
| group | verdict | score | 
|---|---|---|
| #1 | ACCEPTED | 30 | 
| #2 | ACCEPTED | 70 | 
| 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 | 2 | details | 
| #13 | ACCEPTED | 0.00 s | 2 | details | 
| #14 | ACCEPTED | 0.00 s | 2 | details | 
| #15 | ACCEPTED | 0.00 s | 2 | details | 
| #16 | ACCEPTED | 0.01 s | 2 | details | 
| #17 | ACCEPTED | 0.00 s | 2 | details | 
| #18 | ACCEPTED | 0.01 s | 2 | details | 
| #19 | ACCEPTED | 0.01 s | 2 | details | 
| #20 | ACCEPTED | 0.01 s | 2 | details | 
| #21 | ACCEPTED | 0.00 s | 2 | details | 
| #22 | ACCEPTED | 0.00 s | 2 | details | 
| #23 | ACCEPTED | 0.02 s | 2 | details | 
| #24 | ACCEPTED | 0.02 s | 2 | details | 
Code
use core::panic;
use std::alloc::{alloc, dealloc, handle_alloc_error, Layout};
use std::io::stdin;
use std::ptr::null_mut;
#[derive(PartialEq, Eq)]
pub enum Room {
    Empty,
    HasCoin,
}
pub struct LinkedListNode<T> {
    pub next: *mut LinkedListNode<T>,
    pub prev: *mut LinkedListNode<T>,
    pub data: T,
}
impl<T> LinkedListNode<T> {
    /// Removes this linked list node
    pub fn remove_this_element(&mut self) {
        unsafe {
            if !self.prev.is_null() {
                (*self.prev).next = self.next;
            }
            if !self.next.is_null() {
                (*self.next).prev = self.prev;
            }
            dealloc(
                self as *mut LinkedListNode<T> as *mut u8,
                Layout::new::<*mut LinkedListNode<T>>(),
            );
        }
    }
}
pub struct LinkedListIter<T> {
    address: *mut LinkedListNode<T>,
    first_node: *mut LinkedListNode<T>,
}
impl<T> Iterator for LinkedListIter<T> {
    type Item = *mut LinkedListNode<T>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.address.is_null() {
            self.address = self.first_node;
            None
        } else {
            let v = Some(self.address);
            self.address = unsafe { (*self.address).next };
            v
        }
    }
}
impl<T> LinkedListIter<T> {
    #[inline]
    pub fn new(first_node: *mut LinkedListNode<T>) -> LinkedListIter<T> {
        LinkedListIter {
            address: first_node,
            first_node,
        }
    }
    #[inline]
    pub fn go_to_address(&mut self, address: *mut LinkedListNode<T>) {
        self.address = address;
    }
}
pub fn fast_method(mut coins: Vec<isize>, mut robot_position: isize) -> (isize, usize) {
    coins.sort_unstable();
    let mut first_coin: *mut LinkedListNode<isize> = null_mut();
    let mut current_coin: *mut LinkedListNode<isize> = null_mut();
    let mut prev_coin: *mut LinkedListNode<isize> = null_mut();
    let mut is_first_coin = true;
    for coin in coins {
        current_coin =
            unsafe { alloc(Layout::new::<LinkedListNode<isize>>()) } as *mut LinkedListNode<isize>;
        if current_coin.is_null() {
            handle_alloc_error(Layout::new::<LinkedListNode<isize>>());
        }
        if is_first_coin {
            first_coin = current_coin;
            unsafe {
                (*first_coin).prev = null_mut() as *mut LinkedListNode<isize>;
            }
            is_first_coin = false;
        } else {
            unsafe {
                (*prev_coin).next = current_coin;
                (*current_coin).prev = prev_coin;
            }
        }
        unsafe {
            (*current_coin).data = coin;
            (*current_coin).next = null_mut();
        }
        prev_coin = current_coin;
    }
    if robot_position == -1 {
        panic!()
    }
    let mut num_coins_collected = 0;
    let mut num_steps_taken = 0;
    let mut coin_iter = LinkedListIter::new(first_coin);
    let mut coin_found = false;
    for coin in &mut coin_iter {
        if unsafe { (*coin).data } > robot_position {
            if unsafe { (*coin).prev }.is_null() {
                coin_iter.go_to_address(coin);
            } else {
                coin_iter.go_to_address(unsafe { (*coin).prev });
            }
            coin_found = true;
            break;
        }
    }
    // There is no coin at a position to the right of the robot
    if !coin_found {
        coin_iter.go_to_address(current_coin);
    }
    loop {
        let (closest_coin, closest_coin_dis);
        let prev_coin = match coin_iter.next() {
            None => break,
            Some(c) => unsafe { &mut *c },
        };
        let disp = robot_position.abs_diff(prev_coin.data);
        match coin_iter.next() {
            None => {
                closest_coin = prev_coin;
                closest_coin_dis = disp;
            }
            Some(c) => {
                let c = unsafe { &mut *c };
                let disc = robot_position.abs_diff(c.data);
                if disc < disp {
                    closest_coin = c;
                    closest_coin_dis = disc;
                } else if disc > disp {
                    closest_coin = prev_coin;
                    closest_coin_dis = disp;
                } else {
                    break;
                }
            }
        }
        robot_position = closest_coin.data;
        if closest_coin.prev.is_null() {
            coin_iter.go_to_address(closest_coin.next);
        } else {
            coin_iter.go_to_address(closest_coin.prev);
        }
        closest_coin.remove_this_element();
        num_coins_collected += 1;
        num_steps_taken += closest_coin_dis;
    }
    (num_steps_taken as isize, num_coins_collected)
}
fn main() {
    let mut n = String::new();
    stdin().read_line(&mut n).unwrap();
    let room_count = n.trim().parse::<usize>().unwrap();
    let mut room_map = String::new();
    stdin().read_line(&mut room_map).unwrap();
    let mut robot_position: isize = -1;
    let rooms =
        room_map[0..room_count]
            .chars()
            .enumerate()
            .map(|(index, room_desc)| match room_desc {
                '*' => Room::HasCoin,
                '.' => Room::Empty,
                'R' => {
                    robot_position = index as isize;
                    Room::Empty
                }
                _ => panic!(),
            });
    let mut coins = Vec::new();
    for (index, room) in rooms.enumerate() {
        if room == Room::HasCoin {
            coins.push(index as isize);
        }
    }
    let answer = fast_method(coins, robot_position);
    println!("{} {}", answer.0, answer.1);
}
Test details
Test 1
Group: 1, 2
Verdict: ACCEPTED
| input | 
|---|
| 1 R  | 
| correct output | 
|---|
| 0 0 | 
| user output | 
|---|
| 0 0 | 
Test 2
Group: 1, 2
Verdict: ACCEPTED
| input | 
|---|
| 10 ...R......  | 
| correct output | 
|---|
| 0 0 | 
| user output | 
|---|
| 0 0 | 
Test 3
Group: 1, 2
Verdict: ACCEPTED
| input | 
|---|
| 10 **.R...***  | 
| correct output | 
|---|
| 12 5 | 
| user output | 
|---|
| 12 5 | 
Test 4
Group: 1, 2
Verdict: ACCEPTED
| input | 
|---|
| 10 ***R******  | 
| correct output | 
|---|
| 0 0 | 
| user output | 
|---|
| 0 0 | 
Test 5
Group: 1, 2
Verdict: ACCEPTED
| input | 
|---|
| 1000 R................................  | 
| correct output | 
|---|
| 947 9 | 
| user output | 
|---|
| 947 9 | 
Test 6
Group: 1, 2
Verdict: ACCEPTED
| input | 
|---|
| 1000 .................................  | 
| correct output | 
|---|
| 886 9 | 
| user output | 
|---|
| 886 9 | 
Test 7
Group: 1, 2
Verdict: ACCEPTED
| input | 
|---|
| 1000 .....*..*....**..**..*......*....  | 
| correct output | 
|---|
| 1287 400 | 
| user output | 
|---|
| 1287 400 | 
Test 8
Group: 1, 2
Verdict: ACCEPTED
| input | 
|---|
| 1000 ************.*****************...  | 
| correct output | 
|---|
| 0 0 | 
| user output | 
|---|
| 0 0 | 
Test 9
Group: 1, 2
Verdict: ACCEPTED
| input | 
|---|
| 1000 ******************************...  | 
| correct output | 
|---|
| 0 0 | 
| user output | 
|---|
| 0 0 | 
Test 10
Group: 1, 2
Verdict: ACCEPTED
| input | 
|---|
| 1000 R*****************************...  | 
| correct output | 
|---|
| 999 999 | 
| user output | 
|---|
| 999 999 | 
Test 11
Group: 1, 2
Verdict: ACCEPTED
| input | 
|---|
| 1000 ******************************...  | 
| correct output | 
|---|
| 999 999 | 
| user output | 
|---|
| 999 999 | 
Test 12
Group: 2
Verdict: ACCEPTED
| input | 
|---|
| 10000 .......**........*...........*...  | 
| correct output | 
|---|
| 10971 999 | 
| user output | 
|---|
| 10971 999 | 
Test 13
Group: 2
Verdict: ACCEPTED
| input | 
|---|
| 10000 *..*....*......*.....*..*........  | 
| correct output | 
|---|
| 9999 999 | 
| user output | 
|---|
| 9999 999 | 
Test 14
Group: 2
Verdict: ACCEPTED
| input | 
|---|
| 10000 *.*.*...**.*...*....**.**.**.....  | 
| correct output | 
|---|
| 18766 5000 | 
| user output | 
|---|
| 18766 5000 | 
Test 15
Group: 2
Verdict: ACCEPTED
| input | 
|---|
| 10000 R*****************************...  | 
| correct output | 
|---|
| 9999 9999 | 
| user output | 
|---|
| 9999 9999 | 
Test 16
Group: 2
Verdict: ACCEPTED
| input | 
|---|
| 10000 ******************************...  | 
| correct output | 
|---|
| 9999 9999 | 
| user output | 
|---|
| 9999 9999 | 
Test 17
Group: 2
Verdict: ACCEPTED
| input | 
|---|
| 200000 .................................  | 
| correct output | 
|---|
| 0 0 | 
| user output | 
|---|
| 0 0 | 
Test 18
Group: 2
Verdict: ACCEPTED
| input | 
|---|
| 200000 .................................  | 
| correct output | 
|---|
| 299934 10000 | 
| user output | 
|---|
| 299934 10000 | 
Test 19
Group: 2
Verdict: ACCEPTED
| input | 
|---|
| 200000 **.***....**..**.....***.*..*....  | 
| correct output | 
|---|
| 299998 100000 | 
| user output | 
|---|
| 299998 100000 | 
Test 20
Group: 2
Verdict: ACCEPTED
| input | 
|---|
| 200000 ******************************...  | 
| correct output | 
|---|
| 0 0 | 
| user output | 
|---|
| 0 0 | 
Test 21
Group: 2
Verdict: ACCEPTED
| input | 
|---|
| 200000 R................................  | 
| correct output | 
|---|
| 133765 3 | 
| user output | 
|---|
| 133765 3 | 
Test 22
Group: 2
Verdict: ACCEPTED
| input | 
|---|
| 200000 R................................  | 
| correct output | 
|---|
| 199982 5000 | 
| user output | 
|---|
| 199982 5000 | 
Test 23
Group: 2
Verdict: ACCEPTED
| input | 
|---|
| 200000 R*****************************...  | 
| correct output | 
|---|
| 199999 199999 | 
| user output | 
|---|
| 199999 199999 | 
Test 24
Group: 2
Verdict: ACCEPTED
| input | 
|---|
| 200000 ******************************...  | 
| correct output | 
|---|
| 199999 199999 | 
| user output | 
|---|
| 199999 199999 | 
