CSES - Putka Open 2020 – 1/5 - Results
Submission details
Task:Vaihdot
Sender:Hennkka
Submission time:2020-09-05 17:38:13 +0300
Language:Rust
Status:READY
Result:100
Feedback
groupverdictscore
#1ACCEPTED13
#2ACCEPTED23
#3ACCEPTED64
Test results
testverdicttimegroup
#1ACCEPTED0.01 s1, 2, 3details
#2ACCEPTED0.01 s1, 2, 3details
#3ACCEPTED0.01 s1, 2, 3details
#4ACCEPTED0.01 s1, 2, 3details
#5ACCEPTED0.01 s1, 2, 3details
#6ACCEPTED0.01 s1, 2, 3details
#7ACCEPTED0.01 s1, 2, 3details
#8ACCEPTED0.01 s1, 2, 3details
#9ACCEPTED0.01 s2, 3details
#10ACCEPTED0.01 s2, 3details
#11ACCEPTED0.01 s2, 3details
#12ACCEPTED0.01 s2, 3details
#13ACCEPTED0.01 s2, 3details
#14ACCEPTED0.01 s2, 3details
#15ACCEPTED0.01 s2, 3details
#16ACCEPTED0.01 s2, 3details
#17ACCEPTED0.24 s3details
#18ACCEPTED0.27 s3details
#19ACCEPTED0.25 s3details
#20ACCEPTED0.25 s3details
#21ACCEPTED0.27 s3details
#22ACCEPTED0.28 s3details
#23ACCEPTED0.43 s3details
#24ACCEPTED0.47 s3details

Compiler report

warning: function is never used: `solve_brute`
  --> input/code.rs:17:4
   |
17 | fn solve_brute(list: Vec<usize>) -> (usize, usize) {
   |    ^^^^^^^^^^^
   |
   = note: `#[warn(dead_code)]` on by default

Code

use std::collections::*;
use std::io::BufRead;
use std::str::FromStr;

fn count_rounds(list: &[usize]) -> usize {
    let mut res = 0;
    let mut seen = vec![false; list.len()];
    for v in list {
        if *v == 1 || !seen[v - 2] {
            res += 1;
        }
        seen[v - 1] = true;
    }
    return res;
}

fn solve_brute(list: Vec<usize>) -> (usize, usize) {
    let mut list = list;
    let mut counts = BTreeMap::<usize, usize>::new();
    for a in 0..list.len() {
        for b in a + 1..list.len() {
            list.swap(a, b);
            counts
                .entry(count_rounds(&list))
                .and_modify(|v| *v += 1)
                .or_insert(1);
            list.swap(a, b);
        }
    }
    counts.into_iter().next().unwrap()
}

#[derive(Clone)]
struct SegTree {
    tree: Vec<isize>,
}

impl SegTree {
    fn new(n: usize) -> Self {
        assert!(n < usize::MAX / 2);
        // TODO: Check that n is power of 2
        Self {
            tree: vec![0; 2 * n],
        }
    }

    fn add(&mut self, i: usize, val: isize) {
        let mut i = i + self.tree.len() / 2;
        while i > 0 {
            self.tree[i] += val;
            i /= 2;
        }
    }

    fn get(&self, l: usize, r: usize) -> isize {
        let mut l = l + self.tree.len() / 2;
        let mut r = r + self.tree.len() / 2;
        let mut res = 0;
        while l < r {
            if l % 2 == 1 {
                res += self.tree[l];
                l += 1;
            }
            if r % 2 == 0 {
                res += self.tree[r];
                r -= 1;
            }
            l /= 2;
            r /= 2;
        }
        if l == r {
            res += self.tree[l];
        }

        res
    }
}

#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)]
struct Event {
    position: usize,
    target: usize,
    list: i8,
    amount: isize,
}

#[derive(Debug)]
struct Ranges {
    target: usize,
    left: usize,
    right: usize,
    outer: i8,
    inner: i8,
}

impl Into<Vec<Event>> for Ranges {
    fn into(self) -> Vec<Event> {
        vec![
            Event {
                target: self.target,
                position: 0,
                list: self.outer,
                amount: 1,
            },
            Event {
                target: self.target,
                position: self.left,
                list: self.outer,
                amount: -1,
            },
            Event {
                target: self.target,
                position: self.left,
                list: self.inner,
                amount: 1,
            },
            Event {
                target: self.target,
                position: self.right,
                list: self.inner,
                amount: -1,
            },
            Event {
                target: self.target,
                position: self.right,
                list: self.outer,
                amount: 1,
            },
        ]
    }
}

fn ranges(indices: &[usize], p: usize) -> Ranges {
    let i = indices[p];
    if p == 1 {
        let nexti = *indices.get(p + 1).unwrap_or(&indices.len());
        return if i < nexti {
            // 1 2
            Ranges {
                target: i,
                left: 0,
                right: nexti + 1,
                outer: 1,
                inner: 0,
            }
        } else {
            // 2 1
            Ranges {
                target: i,
                left: 0,
                right: nexti + 1,
                outer: 0,
                inner: -1,
            }
        };
    }

    let previ = indices[p - 1];
    let nexti = *indices.get(p + 1).unwrap_or(&indices.len());
    if previ < nexti {
        let (outer, inner) = if i < previ {
            //  i pi ni
            (0, -1)
        } else if i < nexti {
            // pi  i ni
            (1, 0)
        } else {
            // pi ni  i
            (0, -1)
        };
        Ranges {
            target: i,
            left: previ + 1,
            right: nexti + 1,
            outer,
            inner,
        }
    } else {
        let (outer, inner) = if i < nexti {
            //  i ni pi
            (0, 1)
        } else if i < previ {
            // ni  i pi
            (-1, 0)
        } else {
            // ni pi  i
            (0, 1)
        };
        Ranges {
            target: i,
            left: nexti + 1,
            right: previ + 1,
            outer,
            inner,
        }
    }
}

fn events(perm: &[usize], indices: &[usize]) -> Vec<Event> {
    let mut events = Vec::new();
    for p in 1..=perm.len() {
        let ev: Vec<_> = ranges(indices, p).into();
        events.extend(ev.into_iter());
        // if previ < nexti {
        //     if i < previ {
        //         //  i pi ni
        //         events.push(Event {
        //             position: 0,
        //             list: 0,
        //             amount: 1,
        //         });
        //         events.push(Event {
        //             position: previ + 1,
        //             list: 0,
        //             amount: -1,
        //         });

        //         events.push(Event {
        //             position: previ + 1,
        //             list: -1,
        //             amount: 1,
        //         });
        //         events.push(Event {
        //             position: nexti + 1,
        //             list: -1,
        //             amount: -1,
        //         });

        //         events.push(Event {
        //             position: nexti + 1,
        //             list: 0,
        //             amount: 1,
        //         });
        //     } else if i < nexti {
        //         // pi  i ni
        //         events.push(Event {
        //             position: 0,
        //             list: 1,
        //             amount: 1,
        //         });
        //         events.push(Event {
        //             position: previ + 1,
        //             list: 1,
        //             amount: -1,
        //         });

        //         events.push(Event {
        //             position: previ + 1,
        //             list: 0,
        //             amount: 1,
        //         });
        //         events.push(Event {
        //             position: nexti + 1,
        //             list: 0,
        //             amount: -1,
        //         });

        //         events.push(Event {
        //             position: nexti + 1,
        //             list: 1,
        //             amount: 1,
        //         });
        //     } else {
        //         // pi ni  i
        //         events.push(Event {
        //             position: 0,
        //             list: 0,
        //             amount: 1,
        //         });
        //         events.push(Event {
        //             position: previ + 1,
        //             list: 0,
        //             amount: -1,
        //         });

        //         events.push(Event {
        //             position: previ + 1,
        //             list: -1,
        //             amount: 1,
        //         });
        //         events.push(Event {
        //             position: nexti + 1,
        //             list: -1,
        //             amount: -1,
        //         });

        //         events.push(Event {
        //             position: nexti + 1,
        //             list: 0,
        //             amount: 1,
        //         });
        //     }
        // } else {
        //     if i < nexti {
        //         //  i ni pi
        //         events.push(Event {
        //             position: 0,
        //             list: 0,
        //             amount: 1,
        //         });
        //         events.push(Event {
        //             position: nexti + 1,
        //             list: 0,
        //             amount: -1,
        //         });

        //         events.push(Event {
        //             position: nexti + 1,
        //             list: 1,
        //             amount: 1,
        //         });
        //         events.push(Event {
        //             position: previ + 1,
        //             list: 1,
        //             amount: -1,
        //         });

        //         events.push(Event {
        //             position: previ + 1,
        //             list: 0,
        //             amount: 1,
        //         });
        //     } else if i < previ {
        //         // ni  i pi
        //         events.push(Event {
        //             position: 0,
        //             list: -1,
        //             amount: 1,
        //         });
        //         events.push(Event {
        //             position: nexti + 1,
        //             list: -1,
        //             amount: -1,
        //         });

        //         events.push(Event {
        //             position: nexti + 1,
        //             list: 0,
        //             amount: 1,
        //         });
        //         events.push(Event {
        //             position: previ + 1,
        //             list: 0,
        //             amount: -1,
        //         });

        //         events.push(Event {
        //             position: previ + 1,
        //             list: -1,
        //             amount: 1,
        //         });
        //     } else {
        //         // ni pi  i
        //         events.push(Event {
        //             position: 0,
        //             list: 0,
        //             amount: 1,
        //         });
        //         events.push(Event {
        //             position: nexti + 1,
        //             list: 0,
        //             amount: -1,
        //         });

        //         events.push(Event {
        //             position: nexti + 1,
        //             list: 1,
        //             amount: 1,
        //         });
        //         events.push(Event {
        //             position: previ + 1,
        //             list: 1,
        //             amount: -1,
        //         });

        //         events.push(Event {
        //             position: previ + 1,
        //             list: 0,
        //             amount: 1,
        //         });
        //     }
        // }
    }

    events
}

fn solve(perm: Vec<usize>) -> (usize, usize) {
    let mut indices = vec![0; perm.len() + 1];
    for (i, p) in perm.iter().enumerate() {
        indices[*p] = i;
    }
    let base_score = count_rounds(&perm);

    let mut events = events(&perm, &indices);
    events.sort();
    const N: usize = 1 << 20;
    let mut trees = [SegTree::new(N), SegTree::new(N), SegTree::new(N)];
    let mut counts = [0; 5];

    let mut events = events.into_iter().peekable();
    for (i, p) in perm.into_iter().enumerate() {
        // println!("i = {}, p = {}", i, p);
        // Update trees based on events
        while events
            .peek()
            .and_then(|e| Some(e.position <= i))
            .unwrap_or(false)
        {
            let event = events.next().unwrap();
            trees[(event.list + 1) as usize].add(event.target, event.amount);
            // println!("Event: {:?}", event);
        }
        // Compute overlapping ranges
        let ranges = ranges(&indices, p);
        // println!("Range: {:?}", ranges);
        for (i, tree) in trees.iter().enumerate() {
            if ranges.left > 0 {
                // println!(
                //     "counts[{} + {}] += {}",
                //     i as isize - 1,
                //     ranges.outer as isize,
                //     tree.get(0, ranges.left - 1)
                // );
                counts[i + (ranges.outer + 1) as usize] += tree.get(0, ranges.left - 1);
            }

            // println!(
            //     "counts[{} + {}] += {}",
            //     i as isize - 1,
            //     ranges.inner as isize,
            //     tree.get(ranges.left, ranges.right - 1)
            // );
            counts[i + (ranges.inner + 1) as usize] += tree.get(ranges.left, ranges.right - 1);

            // println!(
            //     "counts[{} + {}] += {}",
            //     i as isize - 1,
            //     ranges.outer as isize,
            //     tree.get(ranges.right, indices.len() + 2)
            // );
            counts[i + (ranges.outer + 1) as usize] += tree.get(ranges.right, indices.len() + 2);
        }
        // Remove self-effect
        if ranges.left <= i && i < ranges.right {
            // println!("Removing inner counts[{}, {}]", ranges.inner, ranges.inner);
            counts[(2 * ranges.inner + 2) as usize] -= 1;
        } else {
            // println!("Removing outer counts[{}, {}]", ranges.outer, ranges.outer);
            counts[(2 * ranges.outer + 2) as usize] -= 1;
        }
    }

    // println!("Base score: {}", base_score);
    // println!("{:?}", counts);

    for (i, c) in counts.iter().enumerate() {
        if *c > 0 {
            return (base_score + i - 2, *c as usize / 2);
        }
    }

    // solve_brute(perm)
    unreachable!();
}

fn main() {
    let stdin = std::io::stdin();
    let stdin = stdin.lock();
    let mut lines = stdin.lines();
    let n = usize::from_str(&lines.next().unwrap().unwrap()).unwrap();
    let list: Vec<_> = lines
        .next()
        .unwrap()
        .unwrap()
        .split_whitespace()
        .map(|v| usize::from_str(&v).unwrap())
        .collect();
    assert_eq!(list.len(), n);

    let (minimum, possibilities) = solve(list);
    println!("{} {}", minimum, possibilities);
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_count_rounds() {
        assert_eq!(count_rounds(&[1, 2, 3, 4]), 1);
        assert_eq!(count_rounds(&[4, 3, 2, 1]), 4);
        assert_eq!(count_rounds(&[6, 1, 4, 5, 7, 3, 8, 2]), 4);
        assert_eq!(count_rounds(&[6, 3, 4, 5, 7, 1, 8, 2]), 3);
    }

    #[test]
    fn test_brute_solver() {
        assert_eq!(solve_brute(vec![6, 1, 4, 5, 7, 3, 8, 2]), (3, 5));
    }

    struct Permutations {
        state: Option<Vec<usize>>,
    }

    impl Permutations {
        fn new(n: usize) -> Self {
            Self {
                state: Some((1..=n).collect()),
            }
        }
    }

    impl std::iter::Iterator for Permutations {
        type Item = Vec<usize>;

        fn next(&mut self) -> Option<Self::Item> {
            let state = match &mut self.state {
                Some(res) => res,
                None => return None,
            };
            let res = state.clone();

            // Compute next permutation
            let mut i = state.len() - 1;
            loop {
                let i1 = i;
                i -= 1;
                if state[i] < state[i1] {
                    let mut i2 = state.len() - 1;
                    while !(state[i] < state[i2]) {
                        i2 -= 1;
                    }
                    state.swap(i, i2);
                    state[i1..].reverse();
                    return Some(res);
                }
                if i == 0 {
                    self.state = None;
                    return Some(res);
                }
            }
        }
    }

    #[test]
    fn test_against_brute_2() {
        for perm in Permutations::new(2) {
            assert_eq!(
                solve(perm.clone()),
                solve_brute(perm.clone()),
                "Input {:?}",
                perm
            );
        }
    }
    #[test]
    fn test_against_brute_3() {
        for perm in Permutations::new(3) {
            assert_eq!(
                solve(perm.clone()),
                solve_brute(perm.clone()),
                "Input {:?}",
                perm
            );
        }
    }
    #[test]
    fn test_against_brute_4() {
        for perm in Permutations::new(4) {
            assert_eq!(
                solve(perm.clone()),
                solve_brute(perm.clone()),
                "Input {:?}",
                perm
            );
        }
    }
    #[test]
    fn test_against_brute_5() {
        for perm in Permutations::new(5) {
            assert_eq!(
                solve(perm.clone()),
                solve_brute(perm.clone()),
                "Input {:?}",
                perm
            );
        }
    }
    #[test]
    fn test_against_brute_6() {
        for perm in Permutations::new(6) {
            assert_eq!(
                solve(perm.clone()),
                solve_brute(perm.clone()),
                "Input {:?}",
                perm
            );
        }
    }
    #[test]
    fn test_against_brute_7() {
        for perm in Permutations::new(7) {
            assert_eq!(
                solve(perm.clone()),
                solve_brute(perm.clone()),
                "Input {:?}",
                perm
            );
        }
    }

    #[test]
    fn test_speed_200000() {
        use rand::distributions::{Distribution, Uniform};
        use std::time::{Duration, Instant};

        const ITERS: u32 = 30;
        const SIZE: usize = 200000;
        let mut time = Duration::from_nanos(1);
        for i in 0..ITERS {
            let mut input: Vec<usize> = (1..=SIZE).collect();

            for i in 0..SIZE {
                input.swap(i, Uniform::from(i..SIZE).sample(&mut rand::thread_rng()));
            }

            std::sync::atomic::fence(std::sync::atomic::Ordering::AcqRel);
            let start = Instant::now();
            std::sync::atomic::fence(std::sync::atomic::Ordering::AcqRel);
            solve(input);
            std::sync::atomic::fence(std::sync::atomic::Ordering::AcqRel);
            let stop = Instant::now();
            std::sync::atomic::fence(std::sync::atomic::Ordering::AcqRel);
            time += stop - start;
        }

        let time = (time / ITERS).as_secs_f64();
        assert!(time < 1.0, "Took time {}", time);
    }

    fn print_outer(left: usize, right: usize, width: usize) {
        assert!(left < right);
        let right = right.min(width);
        // Left part of the range
        if left > 0 {
            print!("├─{}┤ ", "─".repeat(2 * (left - 1)));
        } else {
            print!("  ");
        }
        if right < width {
            // Middle part
            print!("{}", " ".repeat(2 * (right - left - 1)));
            // Right part
            print!("├─{}┤", "─".repeat(2 * (width - right - 1)));
        }
    }
    fn print_inner(left: usize, right: usize, width: usize) {
        assert!(left < right);
        let right = right.min(width);
        // Padding
        print!("{}", " ".repeat(2 * (left)));
        // Bar
        print!("├─{}┤ ", "─".repeat(2 * (right - left - 1)));
    }

    fn print_ranges(perm: Vec<usize>) {
        let mut indices = vec![0; perm.len() + 1];
        for (i, p) in perm.iter().enumerate() {
            indices[*p] = i;
        }
        println!(
            "    {}",
            perm.iter()
                .map(|p| p.to_string())
                .collect::<Vec<_>>()
                .join(" ")
        );
        for p in 1..=perm.len() {
            let i = indices[p];
            // Print p at correct position
            println!("    {}{}", " ".repeat(2 * i), p);
            let ranges = ranges(&indices, p);
            // println!("{:?}", ranges);
            let mut prints: [Option<fn(usize, usize, usize)>; 3] = [None, None, None];
            prints[(ranges.inner + 1) as usize] = Some(print_inner);
            prints[(ranges.outer + 1) as usize] = Some(print_outer);
            print!("-1 ");
            prints[0].and_then(|f| Some(f(ranges.left, ranges.right, perm.len())));
            println!();
            print!(" 0 ");
            prints[1].and_then(|f| Some(f(ranges.left, ranges.right, perm.len())));
            println!();
            print!("+1 ");
            prints[2].and_then(|f| Some(f(ranges.left, ranges.right, perm.len())));
            println!();
        }
    }

    // #[test]
    // fn foo() {
    //     // ranges(vec![1, 2, 3]);
    //     // solve(vec![1, 2, 3]);
    //     // print_ranges(vec![2, 3, 1]);
    //     // solve(vec![2, 3, 1]);
    //     // ranges(vec![6, 1, 4, 5, 7, 3, 8, 2]);
    //     // solve(vec![6, 1, 4, 5, 7, 3, 8, 2]);
    //     // ranges(vec![2, 1, 3]);
    //     // ranges(vec![1, 2, 3, 4, 5]);

    //     // ranges(vec![1, 3, 2]);
    //     // ranges(vec![2, 3, 1, 4]);
    //     // ranges(vec![3, 1, 2, 4]);

    //     for perm in Permutations::new(4) {
    //         // let start = count_rounds(&perm);
    //         // let best = solve_brute(perm.clone()).0;
    //         // println!("{:?}", perm);
    //         // ranges(perm);
    //         // assert!(best != start, "Input {:?}, {}, {}", perm, best, start);

    //         // assert_eq!(
    //         //     solve(perm.clone()),
    //         //     solve_brute(perm.clone()),
    //         //     "Input {:?}",
    //         //     perm
    //         // );
    //     }
    //     // assert!(false);
    // }
}

Test details

Test 1

Group: 1, 2, 3

Verdict: ACCEPTED

input
100
1 2 3 4 5 6 7 8 9 10 11 12 13 ...

correct output
2 99

user output
2 99

Test 2

Group: 1, 2, 3

Verdict: ACCEPTED

input
100
100 99 98 97 96 95 94 93 92 91...

correct output
98 4851

user output
98 4851

Test 3

Group: 1, 2, 3

Verdict: ACCEPTED

input
100
1 2 88 4 5 6 7 8 9 10 11 12 13...

correct output
16 5

user output
16 5

Test 4

Group: 1, 2, 3

Verdict: ACCEPTED

input
100
51 48 74 70 45 71 24 88 55 99 ...

correct output
49 131

user output
49 131

Test 5

Group: 1, 2, 3

Verdict: ACCEPTED

input
100
45 67 29 62 70 77 41 74 52 95 ...

correct output
52 268

user output
52 268

Test 6

Group: 1, 2, 3

Verdict: ACCEPTED

input
100
47 98 2 75 6 21 84 8 4 89 27 9...

correct output
48 149

user output
48 149

Test 7

Group: 1, 2, 3

Verdict: ACCEPTED

input
100
73 68 17 94 71 63 61 13 58 10 ...

correct output
47 116

user output
47 116

Test 8

Group: 1, 2, 3

Verdict: ACCEPTED

input
100
17 16 45 94 6 1 36 81 31 13 51...

correct output
45 95

user output
45 95

Test 9

Group: 2, 3

Verdict: ACCEPTED

input
5000
1 2 3 4 5 6 7 8 9 10 11 12 13 ...

correct output
2 4999

user output
2 4999

Test 10

Group: 2, 3

Verdict: ACCEPTED

input
5000
5000 4999 4998 4997 4996 4995 ...

correct output
4998 12492501

user output
4998 12492501

Test 11

Group: 2, 3

Verdict: ACCEPTED

input
5000
1 2 3 4 5 6 7 8 9 10 11 12 13 ...

correct output
19 10

user output
19 10

Test 12

Group: 2, 3

Verdict: ACCEPTED

input
5000
1 2 3 4 5 6 264 8 9 10 11 12 1...

correct output
190 96

user output
190 96

Test 13

Group: 2, 3

Verdict: ACCEPTED

input
5000
1 2 3 4 5 6 7 8 9 2400 11 12 1...

correct output
1378 27938

user output
1378 27938

Test 14

Group: 2, 3

Verdict: ACCEPTED

input
5000
4012 2 4820 4208 1868 1728 362...

correct output
2511 436307

user output
2511 436307

Test 15

Group: 2, 3

Verdict: ACCEPTED

input
5000
3877 3972 1112 3669 1959 4640 ...

correct output
2497 417065

user output
2497 417065

Test 16

Group: 2, 3

Verdict: ACCEPTED

input
5000
2774 998 4525 2884 487 1995 41...

correct output
2518 426448

user output
2518 426448

Test 17

Group: 3

Verdict: ACCEPTED

input
200000
1 2 3 4 5 6 7 8 9 10 11 12 13 ...

correct output
2 199999

user output
2 199999

Test 18

Group: 3

Verdict: ACCEPTED

input
200000
200000 199999 199998 199997 19...

correct output
199998 19999700001

user output
199998 19999700001

Test 19

Group: 3

Verdict: ACCEPTED

input
200000
1 2 3 4 5 6 7 8 9 10 11 12 13 ...

correct output
19 10

user output
19 10

Test 20

Group: 3

Verdict: ACCEPTED

input
200000
1 2 3 4 5 6 7 8 9 10 11 12 13 ...

correct output
199 100

user output
199 100

Test 21

Group: 3

Verdict: ACCEPTED

input
200000
1 2 3 4 5 6 7 8 9 10 11 12 13 ...

correct output
1979 1030

user output
1979 1030

Test 22

Group: 3

Verdict: ACCEPTED

input
200000
1 2 184153 4 5 6 7 8 164545 10...

correct output
18081 477187

user output
18081 477187

Test 23

Group: 3

Verdict: ACCEPTED

input
200000
151013 68675 119105 58292 3335...

correct output
86328 318722426

user output
86328 318722426

Test 24

Group: 3

Verdict: ACCEPTED

input
200000
11562 33356 106752 170825 2723...

correct output
99873 663048119

user output
99873 663048119