CSES - Datatähti 2025 alku - Results
Submission details
Task:Kortit II
Sender:EmuBird
Submission time:2024-11-02 14:25:24 +0200
Language:Rust (2021)
Status:READY
Result:8
Feedback
groupverdictscore
#1ACCEPTED3
#2ACCEPTED5
#30
#40
#50
Test results
testverdicttimegroup
#1ACCEPTED0.00 s1, 2, 3, 4, 5details
#2ACCEPTED0.02 s2, 3, 4, 5details
#3--3, 4, 5details
#4--4, 5details
#5--5details
#6--5details

Compiler report

warning: unused variable: `a_plays_1`
  --> input/code.rs:66:60
   |
66 | ...k = Callback { callback: |a_plays_1: &Vec<u32>, b_plays_1: Option<&Vec<u32>>, a_plays_2: Option<&Vec<u32>>, b_plays_2: Option<&Vec<u32...
   |                              ^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_a_plays_1`
   |
   = note: `#[warn(unused_variables)]` on by default

warning: unused variable: `b_plays_1`
  --> input/code.rs:66:82
   |
66 | ...k: |a_plays_1: &Vec<u32>, b_plays_1: Option<&Vec<u32>>, a_plays_2: Option<&Vec<u32>>, b_plays_2: Option<&Vec<u32>>, total_cards: u32, ...
   |                              ^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_b_plays_1`

warning: unused variable: `a_plays_2`
  --> input/code.rs:66:112
   |
66 | ...ays_1: Option<&Vec<u32>>, a_plays_2: Option<&Vec<u32>>, b_plays_2: Option<&Vec<u32>>, total_cards: u32, draws: u32, a_points: u32, b_p...
   |                              ^^^^^^^^^ help: if this is...

Code

use std::cell::RefCell;
use std::collections::HashSet;
use std::io;

const MOD: u128 = 10u128.pow(9) + 7;

fn main() {
    let stdin = io::stdin();

    let t: u32 = {
        let mut input: String = String::new();
        stdin.read_line(&mut input).unwrap();
        input.trim().parse().unwrap()
    };

    for _ in 0..t {
        let values: Vec<u32> = {
            let mut input: String = String::new();
            stdin.read_line(&mut input).unwrap();
            input.trim().split_whitespace().map(|x| x.parse::<u32>().unwrap()).collect()
        };

        let answer = generate_answer(values[0], values[1], values[2]);
        println!("{}", answer);
    }
}

fn generate_answer(total_cards: u32, a_points: u32, b_points: u32) -> u128 {
    let total_points = a_points + b_points;

    if total_points > total_cards || total_points > 0 && (a_points >= total_points || b_points >= total_points) {
        return 0;
    }

    let draws = total_cards - a_points - b_points;
    let mut combinations: RefCell<u32> = RefCell::new(0);

    // Cards [(total_cards - draws + 1), total_cards] are consumed for draws.
    // no-op

    // A wins a_points times.
    // When A uses card (total_cards - draws), it must win. a_points - 1 are still left to be chosen.
    let mut a_plays = Vec::<u32>::from([total_cards - draws]); // This vec has its elements in descending order (largest first).
    // Permutations are not yet taken into account, so drawing cards from largest to smallest is fine.

    let mut a_callback = Callback { callback: |a_plays: &Vec<u32>, _: Option<&Vec<u32>>, _: Option<&Vec<u32>>, _: Option<&Vec<u32>>, total_cards: u32, draws: u32, a_points: u32, b_points: u32, counter: &mut RefCell<u32>| {
        let mut b_plays = Vec::<u32>::new(); // This vec has its elements in the same order as a_plays.
        let mut b_used_cards = HashSet::new();

        let mut b_callback = Callback { callback: |a_plays_1: &Vec<u32>, b_plays_1: Option<&Vec<u32>>, _: Option<&Vec<u32>>, _: Option<&Vec<u32>>, total_cards: u32, draws: u32, a_points: u32, b_points: u32, counter: &mut RefCell<u32>| {
            let a_plays_2: Vec<u32> = {
                let mut a_plays_2_set: HashSet<u32> = (1..=(total_cards - draws)).collect();
                for a in a_plays_1 {
                    a_plays_2_set.remove(a);
                }
                a_plays_2_set.iter().map(|x| *x).collect()
            };

            let mut b_plays_2 = Vec::<u32>::new();
            let mut b_used_cards = HashSet::new(); // TODO: reuse the old set
            for b in b_plays_1.unwrap() {
                b_used_cards.insert(*b);
            }

            //println!("B lose callback: \n\tA plays 1: {:?}\n\tB plays 1: {:?}\n\tA plays 2: {:?}", a_plays_1, b_plays_1, a_plays_2);
            let mut b_win_callback = Callback { callback: |a_plays_1: &Vec<u32>, b_plays_1: Option<&Vec<u32>>, a_plays_2: Option<&Vec<u32>>, b_plays_2: Option<&Vec<u32>>, total_cards: u32, draws: u32, a_points: u32, b_points: u32, counter: &mut RefCell<u32>| {
                counter.replace_with(|x| -> u32 { *x + 1});
            }, total_cards, draws, a_points, b_points, counter};
            choose_b_win(&a_plays_1, &a_plays_2, &b_plays_1.unwrap(), &mut b_plays_2, &mut b_used_cards, total_cards, draws, a_points, b_points, &mut b_win_callback);
        }, total_cards, draws, a_points, b_points, counter};
        choose_b_lose(&a_plays, &mut b_plays, &mut b_used_cards, total_cards, draws, a_points, b_points, &mut b_callback);
    }, total_cards, draws, a_points, b_points, counter: &mut combinations};
    choose_a_win(a_points, &mut a_plays, &mut a_callback);

    let mut combinations: u128 = combinations.take() as u128;

    // The cards resulting in draws could be any card.
    combinations = (combinations % MOD) * (nCr(total_cards as u128, draws as u128) % MOD);

    let combinations_with_permutations = combinations * (factorial(total_cards as u128) % MOD);
    combinations_with_permutations % MOD
}

fn nCr(n: u128, k: u128) -> u128 {
    if k > n {
        0
    } else {
        factorial(n) / (factorial(k) * factorial(n - k))
    }
}

fn factorial(n: u128) -> u128 {
    (1..=n).product::<u128>()
}

struct Callback<'a> {
    callback: fn(&Vec<u32>, Option<&Vec<u32>>, Option<&Vec<u32>>, Option<&Vec<u32>>, u32, u32, u32, u32, &mut RefCell<u32>),
    total_cards: u32,
    draws: u32,
    a_points: u32,
    b_points: u32,
    counter: &'a mut RefCell<u32>
}

impl Callback<'_> {
    fn invoke(&mut self, plays_a_1: &Vec<u32>, plays_b_1: Option<&Vec<u32>>, plays_a_2: Option<&Vec<u32>>, plays_b_2: Option<&Vec<u32>>) {
        (self.callback)(plays_a_1, plays_b_1, plays_a_2, plays_b_2, self.total_cards, self.draws, self.a_points, self.b_points, self.counter);
    }
}

fn choose_a_win(a_points: u32, a_plays: &mut Vec<u32>, callback: &mut Callback) {
    if a_plays.len() >= a_points as usize {
        callback.invoke(a_plays, None, None, None);
        return;
    }

    let max = a_plays.last().unwrap() - 1;
    let min = 1 + a_points - a_plays.len() as u32;

    // The card must be between [min, max].
    for a_card in min..=max {
        a_plays.push(a_card);
        choose_a_win(a_points, a_plays, callback);
        a_plays.pop();
    }
}

fn choose_b_lose(a_plays: &Vec<u32>, b_plays: &mut Vec<u32>, b_used_cards: &mut HashSet<u32>, total_cards: u32, draws: u32, a_points: u32, b_points: u32, callback: &mut Callback) {
    if b_plays.len() >= a_plays.len() {
        callback.invoke(a_plays, Some(b_plays), None, None);
        return;
    }

    let max = a_plays[b_plays.len()] - 1;
    let mut range = 1..=max;

    if b_plays.len() == a_plays.len() - 1 && !b_used_cards.contains(&1) {
        range = 1..=1; // If this is the last card and 1 hasn't been used yet, it must be used now.
    }

    for b_card in range {
        if b_used_cards.contains(&b_card) {
            continue;
        }
        b_used_cards.insert(b_card);
        b_plays.push(b_card);
        choose_b_lose(a_plays, b_plays, b_used_cards, total_cards, draws, a_points, b_points, callback);
        b_plays.pop();
        b_used_cards.remove(&b_card);
    }
}


fn choose_b_win(a_plays_1: &Vec<u32>, a_plays_2: &Vec<u32>, b_plays_1: &Vec<u32>, b_plays_2: &mut Vec<u32>, b_used_cards: &mut HashSet<u32>, total_cards: u32, draws: u32, a_points: u32, b_points: u32, callback: &mut Callback) {
    if b_plays_2.len() >= b_points as usize {
        callback.invoke(a_plays_1, Some(b_plays_2), Some(a_plays_1), Some(b_plays_2));
        return;
    }

    let max = total_cards - draws;
    let min = a_plays_2[b_plays_2.len()] + 1;
    let range = min..=max;

    for b_card in range {
        if b_used_cards.contains(&b_card) {
            continue;
        }
        b_used_cards.insert(b_card);
        b_plays_2.push(b_card);
        choose_b_win(a_plays_1 , a_plays_2, b_plays_1, b_plays_2, b_used_cards, total_cards, draws, a_points, b_points, callback);
        b_plays_2.pop();
        b_used_cards.remove(&b_card);
    }
}

Test details

Test 1

Group: 1, 2, 3, 4, 5

Verdict: ACCEPTED

input
54
4 4 0
3 1 3
3 2 2
4 0 4
...

correct output
0
0
0
0
0
...

user output
0
0
0
0
0
...

Test 2

Group: 2, 3, 4, 5

Verdict: ACCEPTED

input
284
6 1 0
5 0 2
7 1 5
7 7 5
...

correct output
0
0
35280
0
36720
...

user output
0
0
35280
0
36720
...

Test 3

Group: 3, 4, 5

Verdict:

input
841
19 3 12
19 19 13
19 7 13
20 11 15
...

correct output
40291066
0
0
0
0
...

user output
(empty)

Test 4

Group: 4, 5

Verdict:

input
1000
15 12 6
7 1 6
44 4 26
6 6 5
...

correct output
0
5040
494558320
0
340694548
...

user output
(empty)

Test 5

Group: 5

Verdict:

input
1000
892 638 599
966 429 655
1353 576 1140
1403 381 910
...

correct output
0
0
0
249098285
0
...

user output
(empty)

Test 6

Group: 5

Verdict:

input
1000
2000 1107 508
2000 1372 249
2000 588 65
2000 1739 78
...

correct output
750840601
678722180
744501884
159164549
868115056
...

user output
(empty)