Last active
March 29, 2024 01:55
-
-
Save magurofly/3ace701334588aed6920e238bd240075 to your computer and use it in GitHub Desktop.
cargo-compete (AtCoder) compete.toml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Path to the test file (Liquid template) | |
# | |
# Variables: | |
# | |
# - `manifest_dir`: Package directory | |
# - `contest`: Contest ID (e.g. "abc100") | |
# - `bin_name`: Name of a `bin` target (e.g. "abc100-a") | |
# - `bin_alias`: "Alias" for a `bin` target defined in `pacakge.metadata.cargo-compete` (e.g. "a") | |
# - `problem`: Alias for `bin_alias` (deprecated) | |
# | |
# Additional filters: | |
# | |
# - `kebabcase`: Convert to kebab case (by using the `heck` crate) | |
test-suite = "{{ manifest_dir }}/testcases/{{ bin_alias }}.yml" | |
# Open files with the command (`jq` command that outputs `string[] | string[][]`) | |
# | |
# VSCode: | |
#open = '[["code", "-a", .manifest_dir], ["code"] + (.paths | map([.src, .test_suite]) | flatten)]' | |
# Emacs: | |
#open = '["emacsclient", "-n"] + (.paths | map([.src, .test_suite]) | flatten)' | |
[template] | |
src = ''' | |
#![allow(dead_code, unused_imports, unused_macros, non_snake_case)] | |
fn main() { | |
input! { | |
} | |
} | |
type Int = i64; | |
const MOD: Int = 998244353; | |
// const MOD: Int = 1_000_000_007; | |
const INF: Int = 1_000_000_000_000_000_000; | |
const YESNO: [&'static str; 2] = ["Yes", "No"]; | |
use proconio::{input, input_interactive, marker::{Chars, Bytes, Usize1}, source::line::LineSource}; | |
use std::*; | |
use std::ops::*; | |
use collections::*; // (BTree|Hash)(Set|Map), BinaryHeap, VecDeque, LinkedList | |
use cmp::{self, Reverse}; // cmp::{min, max} | |
// use itertools::*; | |
use num_traits::*; | |
use num_integer::*; | |
fn yes() { println!("{}", YESNO[0]); } | |
fn no() { println!("{}", YESNO[1]); } | |
fn yesno(c: bool) { println!("{}", if c { YESNO[0] } else { YESNO[1] }); } | |
fn say<T: std::fmt::Display>(x: T) -> T { println!("{}", x); x } | |
fn neighbor4<F: FnMut(usize, usize)>(i: usize, j: usize, h: usize, w: usize, mut f: F) { if i > 0 { (f)(i - 1, j); } if i < h - 1 { (f)(i + 1, j); } if j > 0 { (f)(i, j - 1); } if j < w - 1 { (f)(i, j + 1); } } | |
trait MyItertools : Iterator + Sized { | |
fn to_vec(self) -> Vec<Self::Item> { self.collect::<Vec<_>>() } | |
fn to_vec_rev(self) -> Vec<Self::Item> { let mut v = self.collect::<Vec<_>>(); v.reverse(); v } | |
fn tally(self) -> HashMap<Self::Item, usize> where Self::Item: Copy + Eq + hash::Hash { let mut counts = HashMap::new(); self.for_each(|item| *counts.entry(item).or_default() += 1 ); counts } | |
fn count_if<P: Fn(&Self::Item) -> bool>(self, predicate: P) -> usize { self.filter(predicate).count() } | |
fn implode(self, sep: &str) -> String where Self::Item: std::string::ToString { self.map(|x| x.to_string()).to_vec().join(sep) } | |
fn mex(self, gen: impl IntoIterator<Item = Self::Item>) -> Self::Item where Self::Item: Ord { let mut v = self.collect::<Vec<_>>(); v.sort(); v.dedup(); let mut it = v.into_iter(); gen.into_iter().find(|a| if let Some(x) = it.next() { a != &x } else { true }).unwrap() } | |
} | |
impl<T: ?Sized> MyItertools for T where T: Iterator + Sized {} | |
trait MyOrd : PartialOrd + Sized { | |
fn chmax(&mut self, mut rhs: Self) -> bool { if self < &mut rhs { *self = rhs; true } else { false } } | |
fn chmin(&mut self, mut rhs: Self) -> bool { if self > &mut rhs { *self = rhs; true } else { false } } | |
} | |
impl<T: Sized + PartialOrd> MyOrd for T {} | |
trait MyPrimInt : PrimInt { | |
/// `self ** e` を `m` で割ったあまりを返す | |
fn mod_pow(self, mut e: Self, m: Self) -> Self { let (mut a, mut r) = (self, Self::one()); while e > Self::zero() { if e & Self::one() == Self::one() { r = r * a % m; } a = a * a % m; e = e >> 1; } r } | |
/// 互いに素な場合、 `mod m` における `self` の逆元、そうでない場合、 `self * inv % m == gcd(self, m)` となるような `Err(inv)` を返す | |
fn mod_inv(self, m: Self) -> Result<Self, Self> { let (g, i) = self.ext_gcd(m); if g.is_one() { Ok(i) } else { Err(i) } } | |
/// 素数判定をする。 `self < 2**64` の場合は `O(log self)` 、そうでなければ `O(sqrt self)` | |
fn is_prime(self) -> bool { let u = Self::zero().count_zeros() - self.leading_zeros(); if u <= 8 || u > 64 { self._is_prime_sqrt() } else { self._is_prime_miller_rabin(&if u <= 32 { vec![2, 7, 61] } else { vec![2, 3, 5, 7, 11, 13, 17] }.into_iter().map(MyPrimInt::convert).collect::<Vec<_>>()) } } | |
fn _is_prime_sqrt(self) -> bool { let mut k = 2.convert(); while k * k <= self { if (self % k).is_zero() { return false; } k = k + Self::one(); } true } | |
fn _is_prime_miller_rabin(self, bases: &[Self]) -> bool { if self <= Self::one() { return false; } for &a in bases { if self == a { return true; } if (self % a).is_zero() { return false; } } let mut d = self - Self::one(); d = d >> d.trailing_zeros() as usize; for &a in bases { let mut t = d; let mut y = a.mod_pow(t, self); while !(self - t).is_one() && !y.is_one() && !(self - y).is_one() { y = y * y % self; t = t << 1; } if !(self - y).is_one() && (t % 2.convert()).is_zero() { return false; } } true } | |
/// 拡張ユークリッドの互助法 `(gcd(self, a), x)` s.t. `self * x + a * y == gcd(self, a)` for some y | |
// fn ext_gcd(self, a: Self) -> (Self, Self, Self) { if self < a { let (g, y, x) = a.ext_gcd(self); (g, x, y) } else if a.is_zero() { (self, Self::one(), Self::one()) } else { let (g, y, x) = a.ext_gcd(self % a); (g, x, y - x * (self / a)) } } | |
fn ext_gcd(self, x: Self) -> (Self, Self) { let y = self % x; if y.is_zero() { return (x, y); } let (mut p, mut q) = ((x, Self::zero()), (y, Self::one())); while !q.0.is_zero() { let u = p.0 / q.0; p = (p.0 - q.0 * u, p.1 - q.1 * u); std::mem::swap(&mut p, &mut q); } if p.0 < Self::zero() { p.0 = p.0 + x / p.0; } p } | |
/// `(self / other).ceil()` | |
fn ceiling_div(self, other: Self) -> Self { (self + other - Self::one()) / other } | |
/// `(self / unit).floor() * unit` | |
fn align_floor(self, unit: Self) -> Self { (self / unit) * unit } | |
/// `(self / unit).ceil() * unit` | |
fn align_ceil(self, unit: Self) -> Self { self.ceiling_div(unit) * unit } | |
/// 他の整数型に変換する | |
fn convert<T: PrimInt>(self) -> T { <T as NumCast>::from(self).unwrap() } | |
fn pow(self, mut e: Self) -> Self { let (mut a, mut r) = (self, Self::one()); while e > Self::zero() { if e & Self::one() == Self::one() { r = r * a; } a = a * a; e = e >> 1; } r } | |
/// base を基数としたときの各桁を求める( 0 のときは vec![0] ) | |
fn digits(mut self, base: Self) -> Vec<Self> { assert!(base > Self::zero()); let mut d = vec![]; while self != Self::zero() { d.push(self % base); self = self / base; } d.reverse(); if d.is_empty() { d.push(Self::zero()); }; d } | |
} | |
impl<T: PrimInt> MyPrimInt for T {} | |
#[derive(Debug, Clone, Default)] | |
pub struct BTreeMultiset<T: Ord> { len: usize, set: BTreeMap<T, usize> } | |
impl<'a, T: Ord> BTreeMultiset<T> { | |
pub fn new() -> Self { Self { len: 0, set: BTreeMap::new() } } | |
pub fn len(&self) -> usize { self.len } | |
pub fn count(&self, x: &T) -> usize { self.set.get(x).copied().unwrap_or(0) } | |
pub fn insert_multiple(&mut self, x: T, count: usize) -> usize { self.len += count; let n = self.set.entry(x).or_insert(0); *n += count; *n } | |
pub fn insert(&mut self, x: T) -> usize { self.insert_multiple(x, 1) } | |
pub fn remove_multiple(&mut self, x: &T, count: usize) -> usize { if let Some(n) = self.set.get_mut(x) { let n0 = *n; *n = n0.saturating_sub(count); let n = *n; self.len -= n0 - n; if n == 0 { self.set.remove(x); } n } else { 0 } } | |
pub fn remove(&mut self, x: &T) -> usize { self.remove_multiple(x, 1) } | |
pub fn iter(&'a self) -> btree_map::Iter<'a, T, usize> { self.set.iter() } | |
pub fn into_iter(self) -> btree_map::IntoIter<T, usize> { self.set.into_iter() } | |
pub fn keys(&'a self) -> btree_map::Keys<'a, T, usize> { self.set.keys() } | |
pub fn range(&'a self, range: impl RangeBounds<T>) -> btree_map::Range<'a, T, usize> { self.set.range(range) } | |
} | |
''' | |
[template.new] | |
# `edition` for `Cargo.toml`. | |
edition = "2018" | |
# `profile` for `Cargo.toml`. | |
# | |
# By setting this, you can run tests with `opt-level=3` while enabling `debug-assertions` and `overflow-checks`. | |
#profile = ''' | |
#[dev] | |
#opt-level = 3 | |
#''' | |
dependencies = ''' | |
ac-library-rs = "=0.1.1" | |
once_cell = "=1.18.0" | |
static_assertions = "=1.1.0" | |
varisat = "=0.2.2" | |
memoise = "=0.3.2" | |
argio = "=0.2.0" | |
bitvec = "=1.0.1" | |
counter = "=0.5.7" | |
hashbag = "=0.1.11" | |
pathfinding = "=4.3.0" | |
recur-fn = "=2.2.0" | |
indexing = "=0.4.1" | |
amplify = "=3.14.2" | |
amplify_derive = "=2.11.3" | |
amplify_num = "=0.4.1" | |
easy-ext = "=1.0.1" | |
multimap = "=0.9.0" | |
btreemultimap = "=0.1.1" | |
bstr = "=1.6.0" | |
az = "=1.2.1" | |
glidesort = "=0.1.2" | |
tap = "=1.0.1" | |
omniswap = "=0.1.0" | |
multiversion = "=0.7.2" | |
num = "=0.4.1" | |
num-bigint = "=0.4.3" | |
num-complex = "=0.4.3" | |
num-integer = "=0.1.45" | |
num-iter = "=0.1.43" | |
num-rational = "=0.4.1" | |
num-traits = "=0.2.15" | |
num-derive = "=0.4.0" | |
ndarray = "=0.15.6" | |
nalgebra = "=0.32.3" | |
alga = "=0.9.3" | |
libm = "=0.2.7" | |
rand = "=0.8.5" | |
getrandom = "=0.2.10" | |
rand_chacha = "=0.3.1" | |
rand_core = "=0.6.4" | |
rand_hc = "=0.3.2" | |
rand_pcg = "=0.3.1" | |
rand_distr = "=0.4.3" | |
petgraph = "=0.6.3" | |
indexmap = "=2.0.0" | |
regex = "=1.9.1" | |
lazy_static = "=1.4.0" | |
ordered-float = "=3.7.0" | |
ascii = "=1.1.0" | |
permutohedron = "=0.2.4" | |
superslice = "=1.0.0" | |
itertools = "=0.11.0" | |
itertools-num = "=0.1.3" | |
maplit = "=1.0.2" | |
either = "=1.8.1" | |
im-rc = "=15.1.0" | |
fixedbitset = "=0.4.2" | |
bitset-fixed = "=0.1.0" | |
proconio = { version = "=0.4.5", features = [ "derive" ] } | |
text_io = "=0.1.12" | |
rustc-hash = "=1.1.0" | |
smallvec = "=1.11.0" | |
''' | |
[template.new.copy-files] | |
[new] | |
kind = "cargo-compete" | |
# Platform | |
# | |
# - atcoder | |
# - codeforces | |
# - yukicoder | |
platform = "atcoder" | |
# Path (Liquid template) | |
# | |
# Variables: | |
# | |
# - `contest`: Contest ID. **May be nil** | |
# - `package_name`: Package name | |
path = "./{{ contest }}" | |
#[new] | |
#kind = "oj-api" | |
#url = "https://atcoder.jp/contests/{{ id }}" | |
#path = "./{{ contest }}" | |
# for Library-Checker | |
#[add] | |
#url = "https://judge.yosupo.jp/problem/{{ args[0] }}" | |
##is-contest = ["false"] # optional | |
##target-kind = "bin" # ["bin", "example"]. default to "bin" | |
#bin-name = '{{ args[0] }}' | |
##bin-alias = '{{ args[0] }}' # optional | |
##bin-src-path = './src/bin/{{ bin_alias }}.rs' # optional | |
# for yukicoder | |
#[add] | |
#url = '{% case args[0] %}{% when "contest" %}https://yukicoder.me/contests/{{ args[1] }}{% when "problem" %}https://yukicoder.me/problems/no/{{ args[1] }}{% endcase %}' | |
#is-contest = ["bash", "-c", '[[ $(cut -d / -f 4) == "contests" ]]'] # optional | |
##target-kind = "bin" # ["bin", "example"]. default to "bin" | |
#bin-name = '{% assign segments = url | split: "/" %}{{ segments[5] }}' | |
##bin-alias = '{% assign segments = url | split: "/" %}{{ segments[5] }}' # optional | |
##bin-src-path = './src/bin/{{ bin_alias }}.rs' # optional | |
[test] | |
# Toolchain for the test. (optional) | |
toolchain = "1.70.0" | |
# Profile for `cargo build`. ("dev" | "release") | |
# | |
# Defaults to `"dev"`. | |
#profile = "dev" | |
[submit.transpile] | |
kind = "command" | |
args = ["cargo", "equip", "--exclude-atcoder-202301-crates", "--remove", "docs", "--minify", "libs", "--no-rustfmt", "--bin", "{{ bin_name }}"] | |
language_id = "5054" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment