https://atcoder.jp/contests/abc453/tasks/abc453_e
入力例1だと選手1は単独でチーム、選手2は2人のチームだから、と考えたくなりますが、これだとうまくいきそうにありません。
見る角度を変えて、チームAの人数を決めればよいです。それをAとすると、Aが範囲に入る人数とBが範囲に入る人数とどちらにも入る人数を数えれば、組合せで直ちに求められます。
Aが範囲に入る人数を求めるにはBinary Indexed Treeに全ての範囲を加えればよいです。そして、両方に入るには、AとBを足せば常にNなので、真ん中で折り返して重なる部分を範囲にしてBITに加えればよいです。すなわち、入力例2だと3が真ん中だから、それぞれ、1 3、1 3、2 3、3 3、3 3、2 3となります。
// Team Division #![allow(non_snake_case)] //////////////////// library //////////////////// fn read<T: std::str::FromStr>() -> T { let mut line = String::new(); std::io::stdin().read_line(&mut line).ok(); line.trim().parse().ok().unwrap() } fn read_vec<T: std::str::FromStr>() -> Vec<T> { read::<String>().split_whitespace() .map(|e| e.parse().ok().unwrap()).collect() } // ax = by + 1 (a, b > 0) fn linear_diophantine(a: i64, b: i64) -> Option<(i64, i64)> { if a == 1 { return Some((1, 0)) } let q = b / a; let r = b % a; if r == 0 { return None } let (x1, y1) = linear_diophantine(r, a)?; Some((-q * x1 - y1, -x1)) } fn inverse(a: i64, d: i64) -> i64 { let (x, _y) = linear_diophantine(a, d).unwrap(); if x >= 0 { x % d } else { x % d + d } } //////////////////// Binary Indexed Tree //////////////////// struct BIT { n: usize, data: Vec<i64>, } impl BIT { fn new(n: usize) -> Self { BIT { n, data: vec![0; n + 1] } } // i に x を足す(0-indexedで受け取る) fn add(&mut self, mut i: usize, x: i64) { i += 1; while i <= self.n { self.data[i] += x; i += i & (!i + 1) } } // [0, i] の和(0-indexed) fn sum(&self, mut i: usize) -> i64 { i += 1; let mut s = 0; while i > 0 { s += self.data[i]; i -= i & (!i + 1); } s } } //////////////////// process //////////////////// const D: i64 = 998244353; type Range = (usize, usize); fn read_range() -> Range { let v: Vec<usize> = read_vec(); (v[0], v[1] + 1) } fn read_input() -> Vec<Range> { let N: usize = read(); let ranges: Vec<Range> = (0..N).map(|_| read_range()).collect(); ranges } fn factorials(N: usize) -> Vec<i64> { let mut facs: Vec<i64> = vec![1; N+1]; for i in 1..N+1 { facs[i] = facs[i-1] * (i as i64) % D } facs } fn C(n: i64, m: i64, f: &Vec<i64>) -> i64 { if n < m || m < 0 { 0 } else { f[n as usize] * inverse(f[m as usize], D) % D * inverse(f[(n-m) as usize], D) % D } } fn convert(rngs: &Vec<Range>) -> Vec<Range> { let N = rngs.len(); let mut rngs2: Vec<Range> = vec![]; for &(L, R) in rngs.iter() { if L * 2 > N || (R - 1) * 2 < N { rngs2.push((L, L)) } else { rngs2.push((L.max(N-R+1), N / 2 + 1)) } } rngs2 } fn create_tree(rngs: Vec<Range>) -> BIT { let N = rngs.len(); let mut bit = BIT::new(N.next_power_of_two()); for (l, r) in rngs { bit.add(l, 1); if r < bit.n { bit.add(r, -1) } } bit } fn F(rngs: Vec<Range>) -> i64 { let N = rngs.len(); let rngs2 = convert(&rngs); let facs = factorials(N); let bit = create_tree(rngs); let bit2 = create_tree(rngs2); let mut counter: i64 = 0; for A in 1..N/2+1 { let NA = bit.sum(A); let NB = bit.sum(N-A); let NAB = bit2.sum(A); // AにもBにもなり得る人数 // AにもBにもならない選手がいる if NA + NB - NAB < (N as i64) { continue } // NA - NABは固定 // NB - NABも固定 // NABが動く // A-(NA-NAB)はNABの中でA側 let c = C(NAB, NA-(A as i64), &facs); if A * 2 == N { counter += c } else { counter += c * 2 } } counter % D } fn main() { let rngs = read_input(); println!("{}", F(rngs)) }