結果
問題 | No.2985 May Count Induced C4 Subgraphs |
ユーザー |
![]() |
提出日時 | 2024-12-10 21:30:01 |
言語 | Rust (1.83.0 + proconio) |
結果 |
AC
|
実行時間 | 2,041 ms / 5,000 ms |
コード長 | 22,808 bytes |
コンパイル時間 | 19,415 ms |
コンパイル使用メモリ | 377,756 KB |
実行使用メモリ | 35,332 KB |
最終ジャッジ日時 | 2024-12-10 21:30:42 |
合計ジャッジ時間 | 33,885 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge4 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 22 |
ソースコード
// 0: 0000// 1: 0011// 2: 0112// 3: 0222// 4: 1113// 5: 1122// 6: 1223// 7: 2222// 8: 2233// 9: 3333type M = ModInt<998244353>;fn main() {input! {n: usize,m: usize,e: [(usize1, usize1); m],}if n < 4 {println!("0 0");return;}let mut deg = vec![0; n];for &(a, b) in e.iter() {deg[a] += 1;deg[b] += 1;}let pc = Precalc::new(n + m);let mut mat = vec![];// C(V, 4)mat.push(([1; 11], pc.binom(n, 4)));// E * C(V - 2, 2)mat.push(([0, 1, 2, 3, 2, 3, 3, 4, 4, 5, 6],pc.binom(n - 2, 2) * M::from(m),));// sum_v C(D(v), 2) * (V-3)let s = deg.iter().fold(M::zero(), |s, d| s + pc.binom(*d, 2)) * M::from(n - 3);mat.push(([0, 0, 1, 3, 0, 3, 2, 5, 4, 8, 12], s));// C_3 * (V-3)let mut cnt = 0;enumerate_triangles(n, e.clone(), |_, _, _, _, _, _| cnt += 1);mat.push(([0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 4], M::from(cnt * (n - 3))));// C(E, 2) - sum_v C(D(v), 2)let s = pc.binom(m, 2) - deg.iter().fold(M::zero(), |s, d| s + pc.binom(*d, 2));mat.push(([0, 0, 0, 0, 1, 0, 1, 1, 2, 2, 3], s));// sum_v C(D(v), 3)let s = deg.iter().fold(M::zero(), |s, d| s + pc.binom(*d, 3));mat.push(([0, 0, 0, 0, 0, 1, 0, 1, 0, 2, 4], s));// sum_{(u, v) \in E} (D(v)-1)(D(u)-1) - 3C_3let s = M::from(e.iter().fold(0, |s, e| s + (deg[e.0] - 1) * (deg[e.1] - 1)) - 3 * cnt);mat.push(([0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 12], s));// sum_{c is C_3} sum_{v \in c} (D(v)-2)let mut sum = 0;enumerate_triangles(n, e.clone(), |a, b, c, _, _, _| {for &a in [a, b, c].iter() {sum += deg[a] - 2;}});mat.push(([0, 0, 0, 0, 0, 0, 0, 1, 0, 4, 12], M::from(sum)));// C_4let cnt = count_c4(n, e.clone());mat.push(([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 3], M::from(cnt)));// sum_e C(#{c|c is C3, e \in c}, 2)let mut memo = vec![0; m];enumerate_triangles(n, e.clone(), |_, _, _, x, y, z| {memo[x] += 1;memo[y] += 1;memo[z] += 1;});let s = memo.iter().fold(M::zero(), |s, a| s + pc.binom(*a, 2));mat.push(([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 6], s));let mut mat = mat.into_iter().map(|m| {let mut a = [M::zero(); 12];for i in 0..11 {a[i] = M::new(m.0[i]);}a[11] = m.1;a}).collect::<Vec<_>>();let order = [1, 2, 3, 4, 5, 6, 7, 9, 10];let mut po = 0;for &x in order.iter() {if let Some(y) = (po..mat.len()).find(|v| !mat[*v][x].is_zero()) {mat.swap(y, po);let mut src = mat[po];let inv = src[x].inv();for s in src.iter_mut() {*s *= inv;}for mat in mat.iter_mut() {let m = mat[x];for (mat, s) in mat.iter_mut().zip(src.iter()) {*mat -= *s * m;}}mat[po] = src;po += 1;}}let mut last = mat.pop().unwrap();let inv = last[0].inv();for v in last.iter_mut() {*v *= inv;}println!("{} {}", last[8], last[11]);}pub fn count_c4(n: usize, e: Vec<(usize, usize)>) -> usize {let mut deg = vec![0; n];for &(a, b) in e.iter() {deg[a] += 1;deg[b] += 1;}let mut ord = (0..n).collect::<Vec<_>>();ord.sort_by_key(|x| deg[*x]);let mut inv = vec![0; n];for i in 0..n {inv[ord[i]] = i;}let mut g = deg.iter().map(|d| Vec::with_capacity(*d)).collect::<Vec<_>>();for &(a, b) in e.iter() {g[a].push(b);g[b].push(a);}for g in g.iter_mut() {g.sort_by_key(|v| inv[*v]);}let mut ans = 0;let mut dp = vec![0; n];for &v in ord.iter().rev() {let list = std::mem::take(&mut g[v]);for &u in list.iter() {g[u].pop();for &w in g[u].iter() {ans += dp[w];dp[w] += 1;}}for &u in list.iter() {for &w in g[u].iter() {dp[w] = 0;}}}ans}pub fn enumerate_triangles<F>(n: usize, e: Vec<(usize, usize)>, mut f: F)whereF: FnMut(usize, usize, usize, usize, usize, usize),{assert!(e.iter().all(|e| e.0 != e.1 && e.0.max(e.1) < n));let mut deg = vec![0; n];for e in e.iter() {deg[e.0] += 1;deg[e.1] += 1;}let mut g = deg.iter().map(|d| Vec::with_capacity(*d)).collect::<Vec<_>>();for (i, &(mut a, mut b)) in e.iter().enumerate() {if (deg[a], a) > (deg[b], b) {std::mem::swap(&mut a, &mut b);}g[a].push((b, i));}let mut elem = vec![!0; n];for (a, ga) in g.iter().enumerate() {for &b in ga.iter() {g[b.0].iter().for_each(|c| elem[c.0] = c.1);ga.iter().filter(|c| elem[c.0] != !0).for_each(|c| f(a, b.0, c.0, b.1, c.1, elem[c.0]));g[b.0].iter().for_each(|c| elem[c.0] = !0);}}}// ---------- begin input macro ----------// reference: https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8#[macro_export]macro_rules! input {(source = $s:expr, $($r:tt)*) => {let mut iter = $s.split_whitespace();input_inner!{iter, $($r)*}};($($r:tt)*) => {let s = {use std::io::Read;let mut s = String::new();std::io::stdin().read_to_string(&mut s).unwrap();s};let mut iter = s.split_whitespace();input_inner!{iter, $($r)*}};}#[macro_export]macro_rules! input_inner {($iter:expr) => {};($iter:expr, ) => {};($iter:expr, $var:ident : $t:tt $($r:tt)*) => {let $var = read_value!($iter, $t);input_inner!{$iter $($r)*}};}#[macro_export]macro_rules! read_value {($iter:expr, ( $($t:tt),* )) => {( $(read_value!($iter, $t)),* )};($iter:expr, [ $t:tt ; $len:expr ]) => {(0..$len).map(|_| read_value!($iter, $t)).collect::<Vec<_>>()};($iter:expr, chars) => {read_value!($iter, String).chars().collect::<Vec<char>>()};($iter:expr, bytes) => {read_value!($iter, String).bytes().collect::<Vec<u8>>()};($iter:expr, usize1) => {read_value!($iter, usize) - 1};($iter:expr, $t:ty) => {$iter.next().unwrap().parse::<$t>().expect("Parse error")};}// ---------- end input macro ----------use std::ops::*;// ---------- begin trait ----------pub trait Zero: Sized + Add<Self, Output = Self> {fn zero() -> Self;fn is_zero(&self) -> bool;}pub trait One: Sized + Mul<Self, Output = Self> {fn one() -> Self;fn is_one(&self) -> bool;}pub trait SemiRing: Zero + One {}pub trait Ring: SemiRing + Sub<Output = Self> + Neg<Output = Self> {}pub trait Field: Ring + Div<Output = Self> {}impl<T> SemiRing for T where T: Zero + One {}impl<T> Ring for T where T: SemiRing + Sub<Output = Self> + Neg<Output = Self> {}impl<T> Field for T where T: Ring + Div<Output = Self> {}// ---------- end trait ----------// ---------- begin modint ----------pub const fn pow_mod(mut r: u32, mut n: u32, m: u32) -> u32 {let mut t = 1;while n > 0 {if n & 1 == 1 {t = (t as u64 * r as u64 % m as u64) as u32;}r = (r as u64 * r as u64 % m as u64) as u32;n >>= 1;}t}pub const fn primitive_root(p: u32) -> u32 {let mut m = p - 1;let mut f = [1; 30];let mut k = 0;let mut d = 2;while d * d <= m {if m % d == 0 {f[k] = d;k += 1;}while m % d == 0 {m /= d;}d += 1;}if m > 1 {f[k] = m;k += 1;}let mut g = 1;while g < p {let mut ok = true;let mut i = 0;while i < k {ok &= pow_mod(g, (p - 1) / f[i], p) > 1;i += 1;}if ok {break;}g += 1;}g}pub const fn is_prime(n: u32) -> bool {if n <= 1 {return false;}let mut d = 2;while d * d <= n {if n % d == 0 {return false;}d += 1;}true}#[derive(Clone, Copy, PartialEq, Eq)]pub struct ModInt<const M: u32>(u32);impl<const M: u32> ModInt<{ M }> {const REM: u32 = {let mut t = 1u32;let mut s = !M + 1;let mut n = !0u32 >> 2;while n > 0 {if n & 1 == 1 {t = t.wrapping_mul(s);}s = s.wrapping_mul(s);n >>= 1;}t};const INI: u64 = ((1u128 << 64) % M as u128) as u64;const IS_PRIME: () = assert!(is_prime(M));const PRIMITIVE_ROOT: u32 = primitive_root(M);const ORDER: usize = 1 << (M - 1).trailing_zeros();const fn reduce(x: u64) -> u32 {let _ = Self::IS_PRIME;let b = (x as u32 * Self::REM) as u64;let t = x + b * M as u64;let mut c = (t >> 32) as u32;if c >= M {c -= M;}c as u32}const fn multiply(a: u32, b: u32) -> u32 {Self::reduce(a as u64 * b as u64)}pub const fn new(v: u32) -> Self {assert!(v < M);Self(Self::reduce(v as u64 * Self::INI))}pub const fn const_mul(&self, rhs: Self) -> Self {Self(Self::multiply(self.0, rhs.0))}pub const fn pow(&self, mut n: u64) -> Self {let mut t = Self::new(1);let mut r = *self;while n > 0 {if n & 1 == 1 {t = t.const_mul(r);}r = r.const_mul(r);n >>= 1;}t}pub const fn inv(&self) -> Self {assert!(self.0 != 0);self.pow(M as u64 - 2)}pub const fn get(&self) -> u32 {Self::reduce(self.0 as u64)}pub const fn zero() -> Self {Self::new(0)}pub const fn one() -> Self {Self::new(1)}}impl<const M: u32> Add for ModInt<{ M }> {type Output = Self;fn add(self, rhs: Self) -> Self::Output {let mut v = self.0 + rhs.0;if v >= M {v -= M;}Self(v)}}impl<const M: u32> Sub for ModInt<{ M }> {type Output = Self;fn sub(self, rhs: Self) -> Self::Output {let mut v = self.0 - rhs.0;if self.0 < rhs.0 {v += M;}Self(v)}}impl<const M: u32> Mul for ModInt<{ M }> {type Output = Self;fn mul(self, rhs: Self) -> Self::Output {self.const_mul(rhs)}}impl<const M: u32> Div for ModInt<{ M }> {type Output = Self;fn div(self, rhs: Self) -> Self::Output {self * rhs.inv()}}impl<const M: u32> AddAssign for ModInt<{ M }> {fn add_assign(&mut self, rhs: Self) {*self = *self + rhs;}}impl<const M: u32> SubAssign for ModInt<{ M }> {fn sub_assign(&mut self, rhs: Self) {*self = *self - rhs;}}impl<const M: u32> MulAssign for ModInt<{ M }> {fn mul_assign(&mut self, rhs: Self) {*self = *self * rhs;}}impl<const M: u32> DivAssign for ModInt<{ M }> {fn div_assign(&mut self, rhs: Self) {*self = *self / rhs;}}impl<const M: u32> Neg for ModInt<{ M }> {type Output = Self;fn neg(self) -> Self::Output {if self.0 == 0 {self} else {Self(M - self.0)}}}impl<const M: u32> std::fmt::Display for ModInt<{ M }> {fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> std::fmt::Result {write!(f, "{}", self.get())}}impl<const M: u32> std::fmt::Debug for ModInt<{ M }> {fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> std::fmt::Result {write!(f, "{}", self.get())}}impl<const M: u32> std::str::FromStr for ModInt<{ M }> {type Err = std::num::ParseIntError;fn from_str(s: &str) -> Result<Self, Self::Err> {let val = s.parse::<u32>()?;Ok(ModInt::new(val))}}impl<const M: u32> From<usize> for ModInt<{ M }> {fn from(val: usize) -> ModInt<{ M }> {ModInt::new((val % M as usize) as u32)}}// ---------- end modint ----------// ---------- begin precalc ----------pub struct Precalc<const MOD: u32> {fact: Vec<ModInt<MOD>>,ifact: Vec<ModInt<MOD>>,inv: Vec<ModInt<MOD>>,}impl<const MOD: u32> Precalc<MOD> {pub fn new(size: usize) -> Self {let mut fact = vec![ModInt::one(); size + 1];let mut ifact = vec![ModInt::one(); size + 1];let mut inv = vec![ModInt::one(); size + 1];for i in 2..=size {fact[i] = fact[i - 1] * ModInt::from(i);}ifact[size] = fact[size].inv();for i in (2..=size).rev() {inv[i] = ifact[i] * fact[i - 1];ifact[i - 1] = ifact[i] * ModInt::from(i);}Self { fact, ifact, inv }}pub fn fact(&self, n: usize) -> ModInt<MOD> {self.fact[n]}pub fn ifact(&self, n: usize) -> ModInt<MOD> {self.ifact[n]}pub fn inv(&self, n: usize) -> ModInt<MOD> {assert!(0 < n);self.inv[n]}pub fn perm(&self, n: usize, k: usize) -> ModInt<MOD> {if k > n {return ModInt::zero();}self.fact[n] * self.ifact[n - k]}pub fn binom(&self, n: usize, k: usize) -> ModInt<MOD> {if n < k {return ModInt::zero();}self.fact[n] * self.ifact[k] * self.ifact[n - k]}}// ---------- end precalc ----------impl<const M: u32> Zero for ModInt<{ M }> {fn zero() -> Self {Self::zero()}fn is_zero(&self) -> bool {self.0 == 0}}impl<const M: u32> One for ModInt<{ M }> {fn one() -> Self {Self::one()}fn is_one(&self) -> bool {self.get() == 1}}// ---------- begin array op ----------struct NTTPrecalc<const M: u32> {sum_e: [ModInt<{ M }>; 30],sum_ie: [ModInt<{ M }>; 30],}impl<const M: u32> NTTPrecalc<{ M }> {const fn new() -> Self {let cnt2 = (M - 1).trailing_zeros() as usize;let root = ModInt::new(ModInt::<{ M }>::PRIMITIVE_ROOT);let zeta = root.pow((M - 1) as u64 >> cnt2);let mut es = [ModInt::zero(); 30];let mut ies = [ModInt::zero(); 30];let mut sum_e = [ModInt::zero(); 30];let mut sum_ie = [ModInt::zero(); 30];let mut e = zeta;let mut ie = e.inv();let mut i = cnt2;while i >= 2 {es[i - 2] = e;ies[i - 2] = ie;e = e.const_mul(e);ie = ie.const_mul(ie);i -= 1;}let mut now = ModInt::one();let mut inow = ModInt::one();let mut i = 0;while i < cnt2 - 1 {sum_e[i] = es[i].const_mul(now);sum_ie[i] = ies[i].const_mul(inow);now = ies[i].const_mul(now);inow = es[i].const_mul(inow);i += 1;}Self { sum_e, sum_ie }}}struct NTTPrecalcHelper<const MOD: u32>;impl<const MOD: u32> NTTPrecalcHelper<MOD> {const A: NTTPrecalc<MOD> = NTTPrecalc::new();}pub trait ArrayAdd {type Item;fn add(&self, rhs: &[Self::Item]) -> Vec<Self::Item>;}impl<T> ArrayAdd for [T]whereT: Zero + Copy,{type Item = T;fn add(&self, rhs: &[Self::Item]) -> Vec<Self::Item> {let mut c = vec![T::zero(); self.len().max(rhs.len())];c[..self.len()].copy_from_slice(self);c.add_assign(rhs);c}}pub trait ArrayAddAssign {type Item;fn add_assign(&mut self, rhs: &[Self::Item]);}impl<T> ArrayAddAssign for [T]whereT: Add<Output = T> + Copy,{type Item = T;fn add_assign(&mut self, rhs: &[Self::Item]) {assert!(self.len() >= rhs.len());self.iter_mut().zip(rhs).for_each(|(x, a)| *x = *x + *a);}}impl<T> ArrayAddAssign for Vec<T>whereT: Zero + Add<Output = T> + Copy,{type Item = T;fn add_assign(&mut self, rhs: &[Self::Item]) {if self.len() < rhs.len() {self.resize(rhs.len(), T::zero());}self.as_mut_slice().add_assign(rhs);}}pub trait ArraySub {type Item;fn sub(&self, rhs: &[Self::Item]) -> Vec<Self::Item>;}impl<T> ArraySub for [T]whereT: Zero + Sub<Output = T> + Copy,{type Item = T;fn sub(&self, rhs: &[Self::Item]) -> Vec<Self::Item> {let mut c = vec![T::zero(); self.len().max(rhs.len())];c[..self.len()].copy_from_slice(self);c.sub_assign(rhs);c}}pub trait ArraySubAssign {type Item;fn sub_assign(&mut self, rhs: &[Self::Item]);}impl<T> ArraySubAssign for [T]whereT: Sub<Output = T> + Copy,{type Item = T;fn sub_assign(&mut self, rhs: &[Self::Item]) {assert!(self.len() >= rhs.len());self.iter_mut().zip(rhs).for_each(|(x, a)| *x = *x - *a);}}impl<T> ArraySubAssign for Vec<T>whereT: Zero + Sub<Output = T> + Copy,{type Item = T;fn sub_assign(&mut self, rhs: &[Self::Item]) {if self.len() < rhs.len() {self.resize(rhs.len(), T::zero());}self.as_mut_slice().sub_assign(rhs);}}pub trait ArrayDot {type Item;fn dot(&self, rhs: &[Self::Item]) -> Vec<Self::Item>;}impl<T> ArrayDot for [T]whereT: Mul<Output = T> + Copy,{type Item = T;fn dot(&self, rhs: &[Self::Item]) -> Vec<Self::Item> {assert!(self.len() == rhs.len());self.iter().zip(rhs).map(|p| *p.0 * *p.1).collect()}}pub trait ArrayDotAssign {type Item;fn dot_assign(&mut self, rhs: &[Self::Item]);}impl<T> ArrayDotAssign for [T]whereT: MulAssign + Copy,{type Item = T;fn dot_assign(&mut self, rhs: &[Self::Item]) {assert!(self.len() == rhs.len());self.iter_mut().zip(rhs).for_each(|(x, a)| *x *= *a);}}pub trait ArrayMul {type Item;fn mul(&self, rhs: &[Self::Item]) -> Vec<Self::Item>;}impl<T> ArrayMul for [T]whereT: Zero + One + Copy,{type Item = T;fn mul(&self, rhs: &[Self::Item]) -> Vec<Self::Item> {if self.is_empty() || rhs.is_empty() {return vec![];}let mut res = vec![T::zero(); self.len() + rhs.len() - 1];for (i, a) in self.iter().enumerate() {for (res, b) in res[i..].iter_mut().zip(rhs.iter()) {*res = *res + *a * *b;}}res}}// transform でlen=1を指定すればNTTになるpub trait ArrayConvolution {type Item;fn transform(&mut self, len: usize);fn inverse_transform(&mut self, len: usize);fn convolution(&self, rhs: &[Self::Item]) -> Vec<Self::Item>;}impl<const M: u32> ArrayConvolution for [ModInt<{ M }>] {type Item = ModInt<{ M }>;fn transform(&mut self, len: usize) {let f = self;let n = f.len();let k = (n / len).trailing_zeros() as usize;assert!(len << k == n);assert!(k <= ModInt::<{ M }>::ORDER);let pre = &NTTPrecalcHelper::<{ M }>::A;for ph in 1..=k {let p = len << (k - ph);let mut now = ModInt::one();for (i, f) in f.chunks_exact_mut(2 * p).enumerate() {let (x, y) = f.split_at_mut(p);for (x, y) in x.iter_mut().zip(y.iter_mut()) {let l = *x;let r = *y * now;*x = l + r;*y = l - r;}now *= pre.sum_e[(!i).trailing_zeros() as usize];}}}fn inverse_transform(&mut self, len: usize) {let f = self;let n = f.len();let k = (n / len).trailing_zeros() as usize;assert!(len << k == n);assert!(k <= ModInt::<{ M }>::ORDER);let pre = &NTTPrecalcHelper::<{ M }>::A;for ph in (1..=k).rev() {let p = len << (k - ph);let mut inow = ModInt::one();for (i, f) in f.chunks_exact_mut(2 * p).enumerate() {let (x, y) = f.split_at_mut(p);for (x, y) in x.iter_mut().zip(y.iter_mut()) {let l = *x;let r = *y;*x = l + r;*y = (l - r) * inow;}inow *= pre.sum_ie[(!i).trailing_zeros() as usize];}}let ik = ModInt::new(2).inv().pow(k as u64);for f in f.iter_mut() {*f *= ik;}}fn convolution(&self, rhs: &[Self::Item]) -> Vec<Self::Item> {if self.len().min(rhs.len()) <= 32 {return self.mul(rhs);}const PARAM: usize = 10;let size = self.len() + rhs.len() - 1;let mut k = 0;while (size + (1 << k) - 1) >> k > PARAM {k += 1;}let len = (size + (1 << k) - 1) >> k;let mut f = vec![ModInt::zero(); len << k];let mut g = vec![ModInt::zero(); len << k];f[..self.len()].copy_from_slice(self);g[..rhs.len()].copy_from_slice(rhs);f.transform(len);g.transform(len);let mut buf = [ModInt::zero(); 2 * PARAM - 1];let buf = &mut buf[..(2 * len - 1)];let pre = &NTTPrecalcHelper::<{ M }>::A;let mut now = ModInt::one();for (i, (f, g)) in f.chunks_exact_mut(2 * len).zip(g.chunks_exact(2 * len)).enumerate(){let mut r = now;for (f, g) in f.chunks_exact_mut(len).zip(g.chunks_exact(len)) {buf.fill(ModInt::zero());for (i, f) in f.iter().enumerate() {for (buf, g) in buf[i..].iter_mut().zip(g.iter()) {*buf = *buf + *f * *g;}}f.copy_from_slice(&buf[..len]);for (f, buf) in f.iter_mut().zip(buf[len..].iter()) {*f = *f + r * *buf;}r = -r;}now *= pre.sum_e[(!i).trailing_zeros() as usize];}f.inverse_transform(len);f.truncate(self.len() + rhs.len() - 1);f}}// ---------- end array op ----------