結果
| 問題 | No.3777 Train Seats |
| コンテスト | |
| ユーザー |
Moss_Local
|
| 提出日時 | 2026-10-23 23:18:45 |
| 言語 | Rust (1.99.0 + proconio + num + itertools + ACL) |
| 結果 |
AC
不安定
|
| 実行時間 | 6 ms / 2,000 ms |
| + 137µs | |
| コード長 | 19,447 bytes |
| 記録 | |
| コンパイル時間 | 10,345 ms |
| コンパイル使用メモリ | 188,780 KB |
| 実行使用メモリ | 9,920 KB |
| 最終ジャッジ日時 | 2026-10-23 23:18:59 |
| 合計ジャッジ時間 | 13,411 ms |
|
ジャッジサーバーID (参考情報) |
judge4_0 / judge3_0 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 50 |
コンパイルメッセージ
warning: unnecessary parentheses around assigned value
--> src/main.rs:559:19
|
559 | self.0 *= (rhs.0 % MOD);
| ^ ^
|
= note: `#[warn(unused_parens)]` (part of `#[warn(unused)]`) on by default
help: remove these parentheses
|
559 - self.0 *= (rhs.0 % MOD);
559 + self.0 *= rhs.0 % MOD;
|
warning: variable does not need to be mutable
--> src/main.rs:66:17
|
66 | let mut $x = iter.next()
| ----^^
| |
| help: remove this `mut`
...
786 | sc!(n);
| ------ in this macro invocation
|
= note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default
= note: this warning originates in the macro `sc` (in Nightly builds, run with -Z macro-backtrace for more info)
ソースコード
// -*- coding: utf-8-unix -*-
#![allow(dead_code, unused_imports, unused_macros, unused_variables)]
use std::cmp::{max, min, Ordering, Reverse};
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
use std::fmt::Debug;
use std::io::{self, Read};
use std::str::FromStr;
const INF_I32: i32 = 1_i32 << 30;
const INF_I64: i64 = 1_i64 << 60;
const INF_I128: i128 = 1_i128 << 120;
const INF_USIZE: usize = usize::MAX / 4;
const INF: i64 = INF_I64;
const UINF: usize = INF_USIZE;
const INF128: i128 = INF_I128;
const MOD1: i64 = 1_000_000_007;
const MOD9: i64 = 998_244_353;
const MOD: i64 = MOD9;
const UMOD: usize = MOD as usize;
// =============================================================================
// Input
// =========================================================================
#[allow(dead_code)]
fn read<T: std::str::FromStr>() -> T {
let mut s = String::new();
std::io::stdin().read_line(&mut s).ok();
s.trim().parse().ok().unwrap()
}
#[allow(dead_code)]
fn read_vec<T: std::str::FromStr>() -> Vec<T> {
read::<String>()
.split_whitespace()
.map(|e| e.parse().ok().unwrap())
.collect()
}
#[allow(dead_code)]
fn read_mat<T: std::str::FromStr>(n: usize) -> Vec<Vec<T>> {
(0..n).map(|_| read_vec()).collect()
}
macro_rules! sc {
($($x:ident),+ $(,)?) => {
sc!(@read usize; $($x),+);
};
($($x:ident : $t:ty),+ $(,)?) => {
let values = read_vec::<String>();
let mut iter = values.into_iter();
$(
let mut $x = iter.next()
.expect("入力不足")
.parse::<$t>()
.expect("パース失敗");
)+
};
(@read $t:ty; $($x:ident),+) => {
let values = read_vec::<$t>();
let mut iter = values.into_iter();
$(
let mut $x = iter.next()
.expect("入力不足");
)+
};
}
macro_rules! vsc {
($x:ident $(,)?) => {
vsc!(@read usize; $x);
};
($x:ident : char $(,)?) => {
let mut $x: Vec<char> = read::<String>().chars().collect();
};
($x:ident : $t:ty $(,)?) => {
vsc!(@read $t; $x);
};
(@read $t:ty; $x:ident) => {
let mut $x = read_vec::<$t>();
};
}
// =============================================================================
// Output / Debug
// =============================================================================
macro_rules! p {
() => {
println!();
};
($value:expr $(,)?) => {
println!("{}", $value);
};
($fmt:literal, $($arg:tt)*) => {
println!($fmt, $($arg)*);
};
}
macro_rules! join {
($iter:expr, $separator:expr $(,)?) => {
($iter)
.into_iter()
.map(|x| x.to_string())
.collect::<Vec<_>>()
.join($separator)
};
}
macro_rules! vp {
($iter:expr $(,)?) => {
println!("{}", join!($iter, " "));
};
($iter:expr, $separator:expr $(,)?) => {
println!("{}", join!($iter, $separator));
};
}
macro_rules! yesno {
($condition:expr $(,)?) => {
println!("{}", if $condition { "Yes" } else { "No" });
};
($condition:expr, $yes:expr, $no:expr $(,)?) => {
println!("{}", if $condition { $yes } else { $no });
};
}
macro_rules! d {
($($value:expr),+ $(,)?) => {
#[cfg(debug_assertions)]
{
eprint!("[{}:{}]", file!(), line!());
$(
eprint!(" {} = {:?}", stringify!($value), &$value);
)+
eprintln!();
}
};
}
// =============================================================================
// Scalar / Vec utilities
// =============================================================================
macro_rules! chmin {
($base:expr, $($value:expr),+ $(,)?) => {{
let mut updated = false;
$(
let value = $value;
if $base > value {
$base = value;
updated = true;
}
)+
updated
}};
}
macro_rules! chmax {
($base:expr, $($value:expr),+ $(,)?) => {{
let mut updated = false;
$(
let value = $value;
if $base < value {
$base = value;
updated = true;
}
)+
updated
}};
}
macro_rules! min {
// collection: Vec、配列、スライスなど
($iter:expr $(,)?) => {{
($iter)
.iter()
.min()
.cloned()
.expect("min! called on an empty iterator")
}};
// 複数の値
($first:expr, $($rest:expr),+ $(,)?) => {{
let mut answer = ($first).clone();
$(
chmin!(answer, ($rest).clone());
)+
answer
}};
}
macro_rules! max {
// collection: Vec、配列、スライスなど
($iter:expr $(,)?) => {{
($iter)
.iter()
.max()
.cloned()
.expect("max! called on an empty iterator")
}};
// 複数の値
($first:expr, $($rest:expr),+ $(,)?) => {{
let mut answer = ($first).clone();
$(
chmax!(answer, ($rest).clone());
)+
answer
}};
}
macro_rules! ndvec {
($value:expr; $len:expr) => {
vec![$value; $len]
};
($value:expr; $len:expr, $($rest:expr),+ $(,)?) => {
vec![ndvec![$value; $($rest),+]; $len]
};
}
macro_rules! prefix_sum {
($values:expr $(,)?) => {{
fn prefix_sum_impl<T>(values: &[T]) -> Vec<T>
where
T: Copy + Default + std::ops::Add<Output = T>,
{
let mut prefix = Vec::with_capacity(values.len() + 1);
prefix.push(T::default());
for &value in values {
let next = *prefix.last().unwrap() + value;
prefix.push(next);
}
prefix
}
prefix_sum_impl(&$values)
}};
}
// 数学的な floor(a / b)。b != 0。
macro_rules! div_floor {
($a:expr, $b:expr $(,)?) => {{
let a = $a;
let b = $b;
let q = a / b;
let r = a % b;
if r != 0 && ((r > 0) != (b > 0)) {
q - 1
} else {
q
}
}};
}
// 数学的な ceil(a / b)。b != 0。
macro_rules! div_ceil {
($a:expr, $b:expr $(,)?) => {{
let a = $a;
let b = $b;
let q = a / b;
let r = a % b;
if r != 0 && ((r > 0) == (b > 0)) {
q + 1
} else {
q
}
}};
}
// =============================================================================
// Integer / floating-point binary search
// =============================================================================
// pred(ok) == true, pred(ng) == false を保ち、最後に true 側の境界を返す。
// ok < ng と ok > ng の双方に対応する。
macro_rules! binsearch {
(ok = $ok:expr, ng = $ng:expr, $pred:expr $(,)?) => {{
let mut ok = $ok;
let mut ng = $ng;
let mut pred = $pred;
while ok.abs_diff(ng) > 1 {
let mid = if ok < ng {
ok + (ng - ok) / 2
} else {
ng + (ok - ng) / 2
};
if pred(mid) {
ok = mid;
} else {
ng = mid;
}
}
ok
}};
}
// false ... true の単調列に対し、最初の true を返す。
// ng は false 側の番兵、ok は true 側の番兵。
macro_rules! first_true {
($ng:expr, $ok:expr, $pred:expr $(,)?) => {
binsearch!(ok = $ok, ng = $ng, $pred)
};
}
// true ... false の単調列に対し、最後の true を返す。
// ok は true 側の番兵、ng は false 側の番兵。
macro_rules! last_true {
($ok:expr, $ng:expr, $pred:expr $(,)?) => {
binsearch!(ok = $ok, ng = $ng, $pred)
};
}
// 浮動小数点版。回数を明示することで停止条件の曖昧さを避ける。
macro_rules! binsearch_f64 {
(ok = $ok:expr, ng = $ng:expr, iter = $iter:expr, $pred:expr $(,)?) => {{
let mut ok = $ok;
let mut ng = $ng;
let mut pred = $pred;
for _ in 0..$iter {
let mid = (ok + ng) * 0.5;
if pred(mid) {
ok = mid;
} else {
ng = mid;
}
}
ok
}};
}
// =============================================================================
// Sorted slice bounds
// =============================================================================
macro_rules! lb {
($slice:expr, $value:expr $(,)?) => {{
let value = $value;
($slice).partition_point(|x| x < &value)
}};
}
macro_rules! ub {
($slice:expr, $value:expr $(,)?) => {{
let value = $value;
($slice).partition_point(|x| x <= &value)
}};
}
// UTIL
macro_rules! neighbors4 {
($y:expr, $x:expr, $h:expr, $w:expr $(,)?) => {{
const DY: [isize; 4] = [-1, 0, 1, 0];
const DX: [isize; 4] = [0, 1, 0, -1];
(0..4).filter_map(move |dir| {
let ny = $y as isize + DY[dir];
let nx = $x as isize + DX[dir];
if 0 <= ny && ny < $h as isize && 0 <= nx && nx < $w as isize {
Some((ny as usize, nx as usize))
} else {
None
}
})
}};
}
macro_rules! run_length {
($iter:expr $(,)?) => {{
let mut result = Vec::new();
for value in $iter {
match result.last_mut() {
Some((last, count)) if *last == value => {
*count += 1usize;
}
_ => {
result.push((value, 1usize));
}
}
}
result
}};
}
macro_rules! vector_compress {
($iter:expr $(,)?) => {{
let values: Vec<_> = ($iter).into_iter().collect();
let mut coordinates = values.clone();
coordinates.sort();
coordinates.dedup();
let compressed = values
.iter()
.map(|value| coordinates.binary_search(value).unwrap())
.collect::<Vec<_>>();
(compressed, coordinates)
}};
}
// =============================================================================
// Map / Set literals and counters
// =============================================================================
macro_rules! map {
($($key:expr => $value:expr),* $(,)?) => {{
let mut map = ::std::collections::BTreeMap::new();
$(map.insert($key, $value);)*
map
}};
}
macro_rules! set {
($($value:expr),* $(,)?) => {{
let mut set = ::std::collections::BTreeSet::new();
$(set.insert($value);)*
set
}};
}
macro_rules! count_map {
($iter:expr $(,)?) => {{
let mut count = BTreeMap::new();
for value in $iter {
*count.entry(value).or_insert(0usize) += 1;
}
count
}};
}
macro_rules! map_add {
($map:expr, $key:expr $(,)?) => {
map_add!($map, $key, 1)
};
($map:expr, $key:expr, $delta:expr $(,)?) => {{
let key = $key;
let delta = $delta;
let map = &mut $map;
*map.entry(key).or_insert(0) += delta;
}};
}
macro_rules! M {
(a :expr ) => {
M::new({ a })
};
}
#[derive(Copy, Clone, Debug)]
pub struct M(i64);
impl M {
fn new(x: i64) -> Self {
M(x.rem_euclid(MOD))
}
fn pow(self, n: usize) -> Self {
match n {
0 => M::new(1),
_ => {
let mut a = self.pow(n >> 1);
a *= a;
if n & 1 == 1 {
a *= self;
}
a
}
}
}
fn inv(self) -> Self {
self.pow((MOD - 2) as usize)
}
}
impl std::ops::Neg for M {
type Output = M;
fn neg(self) -> Self::Output {
Self::new(-self.0)
}
}
impl std::ops::AddAssign<M> for M {
fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
self.0 %= MOD;
}
}
impl std::ops::AddAssign<i64> for M {
fn add_assign(&mut self, rhs: i64) {
*self += M::new(rhs);
}
}
impl std::ops::AddAssign<usize> for M {
fn add_assign(&mut self, rhs: usize) {
*self += M::new(rhs as i64);
}
}
impl<T> std::ops::Add<T> for M
where
M: std::ops::AddAssign<T>,
{
type Output = Self;
fn add(self, other: T) -> Self {
let mut res = self;
res += other;
res
}
}
impl std::ops::SubAssign<M> for M {
fn sub_assign(&mut self, rhs: Self) {
self.0 -= rhs.0;
if self.0 < 0 {
self.0 %= MOD;
self.0 += MOD;
}
}
}
impl std::ops::SubAssign<i64> for M {
fn sub_assign(&mut self, rhs: i64) {
*self -= M::new(rhs);
if (*self).0 < 0 {
self.0 %= MOD;
self.0 += MOD;
}
}
}
impl std::ops::SubAssign<usize> for M {
fn sub_assign(&mut self, rhs: usize) {
*self -= M::new(rhs as i64);
if (*self).0 < 0 {
self.0 %= MOD;
self.0 += MOD;
}
}
}
impl<T> std::ops::Sub<T> for M
where
M: std::ops::SubAssign<T>,
{
type Output = Self;
fn sub(self, other: T) -> Self {
let mut res = self;
res -= other;
res
}
}
impl std::ops::MulAssign<M> for M {
fn mul_assign(&mut self, rhs: Self) {
self.0 %= MOD;
self.0 *= (rhs.0 % MOD);
self.0 %= MOD;
}
}
impl std::ops::MulAssign<i64> for M {
fn mul_assign(&mut self, rhs: i64) {
*self *= M::new(rhs);
}
}
impl std::ops::MulAssign<usize> for M {
fn mul_assign(&mut self, rhs: usize) {
*self *= M::new(rhs as i64);
}
}
impl<T> std::ops::Mul<T> for M
where
M: std::ops::MulAssign<T>,
{
type Output = Self;
fn mul(self, other: T) -> Self {
let mut res = self;
res *= other;
res
}
}
impl std::ops::DivAssign<M> for M {
fn div_assign(&mut self, rhs: Self) {
*self *= rhs.inv();
}
}
impl std::ops::DivAssign<i64> for M {
fn div_assign(&mut self, rhs: i64) {
*self /= M::new(rhs);
}
}
impl std::ops::DivAssign<usize> for M {
fn div_assign(&mut self, rhs: usize) {
*self /= M::new(rhs as i64);
}
}
impl<T> std::ops::Div<T> for M
where
M: std::ops::DivAssign<T>,
{
type Output = Self;
fn div(self, other: T) -> Self {
let mut res = self;
res /= other;
res
}
}
impl std::fmt::Display for M {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl std::ops::Deref for M {
type Target = i64;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for M {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[allow(dead_code)]
pub fn gcd(a: usize, b: usize) -> usize {
if b == 0 {
a
} else {
gcd(b, a % b)
}
}
#[allow(dead_code)]
pub fn lcm(a: usize, b: usize) -> usize {
a / gcd(a, b) * b
}
#[allow(dead_code)]
/// (gcd, x, y)
pub fn extgcd(a: i64, b: i64) -> (i64, i64, i64) {
if b == 0 {
(a, 1, 0)
} else {
let (gcd, x, y) = extgcd(b, a % b);
(gcd, y, x - (a / b) * y)
}
}
#[allow(dead_code)]
/// x ^ n % m
pub fn mod_pow(x: usize, n: usize, m: usize) -> usize {
let mut res = 1;
let mut x = x % m;
let mut n = n;
while n > 0 {
if n & 1 == 1 {
res = (res * x) % m;
}
x = (x * x) % m;
n >>= 1;
}
res
}
pub struct Combination {
m: usize,
f_table: Vec<usize>,
moi: Vec<usize>,
}
impl Combination {
// 0 <= size <= 10^8 is constrained.
pub fn new(mod_num: usize, table_size: usize) -> Self {
Self {
m: mod_num,
f_table: vec![0; table_size],
moi: vec![0; 0],
}
}
pub fn build(&mut self) {
let size = self.f_table.len();
self.f_table = self.fact_table(size, self.m);
self.moi = self.fact_inv_table(size, self.m);
}
fn fact_table(&mut self, len: usize, m: usize) -> Vec<usize> {
let mut res = vec![1; len + 1];
for i in 2..len + 1 {
res[i] = (res[i - 1] * i) % m;
}
res
}
fn fact_inv_table(&mut self, len: usize, m: usize) -> Vec<usize> {
let mut res = vec![1; len + 1];
let mut inv = vec![1; len + 1];
//inv[i] = MOD - inv[MOD%i] * (MOD / i) % MOD
for i in 2..len {
inv[i] = (m - inv[m % i] * (m / i) % m) % m;
res[i] = inv[i] * res[i - 1];
// res[i] = self.mod_inverse(i, m) * res[i - 1];
// res[i] = 1;
res[i] %= m;
}
res
}
pub fn p(&mut self, n: usize, k: usize) -> i64 {
let p = MOD as usize;
if k == 0 {
return 1;
}
if n < k {
0
} else {
let (a1, e1) = self.mod_fact(n, p);
let (a2, e2) = self.mod_fact(k, p);
let (a3, e3) = self.mod_fact(n - k, p);
if e1 > e2 + e3 {
0
} else {
let moi = self.mod_inverse(a3 % p, p);
(a1 * self.mod_inverse(a3 % p, p) % p) as i64
}
}
}
pub fn c(&mut self, n: usize, k: usize) -> i64 {
let p = MOD as usize;
if n == 0 && k == 0 {
return 1;
}
if n == 0 {
return 0;
}
if k == 0 {
return 1;
}
if n < k {
0
} else {
let (a1, e1) = self.mod_fact(n, p);
let (a2, e2) = self.mod_fact(k, p);
let (a3, e3) = self.mod_fact(n - k, p);
if e1 > e2 + e3 {
0
} else {
(((a1 * &self.moi[k]) % p * &self.moi[n - k]) % p) as i64
}
}
}
pub fn h(&mut self, n: usize, k: usize) -> i64 {
return self.c(n + k - 1, k);
}
pub fn factorial(&mut self, n: usize) -> i64 {
return self.p(n, n);
}
fn extgcd(&mut self, a: i64, b: i64) -> (i64, i64, i64) {
if b == 0 {
(a, 1, 0)
} else {
let (gcd, x, y) = extgcd(b, a % b);
(gcd, y, x - (a / b) * y)
}
}
fn mod_inverse(&mut self, a: usize, m: usize) -> usize {
let (_, x, _) = self.extgcd(a as i64, m as i64);
((m as i64 + x) as usize % m) % m
}
fn mod_fact(&mut self, n: usize, p: usize) -> (usize, usize) {
if n == 0 {
(1, 0)
} else {
let (a, b) = self.mod_fact(n / p, p);
let pow = b + n / p;
if n / p % 2 != 0 {
(a * (p - self.f_table[(n % p) as usize]) % p, pow)
} else {
(a * self.f_table[(n % p) as usize] % p, pow)
}
}
}
}
fn main() {
sc!(n);
let mut c: Combination = Combination::new(MOD as usize, 201010);
c.build();
let mut res = M(0);
let ft = c.fact_table(n + 1, UMOD);
for i in 1..=n {
if 2 * i > n + 1 || 3 * i < n {
continue;
}
let t = c.c(i + 1, n + 1 - i * 2);
res += M(t) * ft[i] * ft[n - i];
}
p!(res);
}
Moss_Local