Submission #35260618
Source Code Expand
#![allow(non_snake_case)]
use proconio::*;
use rand::prelude::*;
use rand_pcg::Pcg64Mcg;
fn main() {
get_time();
let input = read_input();
let out = solve(&input);
eprintln!("Time = {:.3}", get_time());
write_output(&out);
}
const TL: f64 = 4.9;
const T0: f64 = 0.015;
const T1: f64 = 0.0025;
/// ランダムな領域を破壊して作り直す焼き鈍し
fn solve(input: &Input) -> Output {
// 外側ほど高い重みを用いると焼き鈍しの途中段階で外側に広げすぎてしまうので序盤は全重み1として最適化
// random playoutの性能を上げたら最終的にそこまで重要でなかった
let mut S = 0;
let mut S2 = 0;
for i in 0..input.N {
for j in 0..input.N {
S += weight((i as i32, j as i32), input.N as i32);
S2 += weight2((i as i32, j as i32), input.N as i32);
}
}
S2 *= 3; // 全重み1だと正規化時のスコアが高くなるので適当に調整
let mut rng = rand_pcg::Pcg64Mcg::seed_from_u64(4823902);
let mut crt_state = State::new(input);
let mut crt: Vec<Rect> = vec![];
let mut best = vec![];
let mut best_score = normalized_score(crt_state.score, &input, S);
let mut iter = 0;
let mut is_deleted = mat![0; input.N * input.N];
// Mの小さい入力はぎっしり詰めるより外側に広げる感じの解になるので最初から正規の重みで最適化
let t0 = if input.ps.len() <= (0.25 * (input.N as f64).powf(1.5)) as usize {
0.0
} else {
0.9
};
while get_time() < TL {
iter += 1;
let t = get_time() / TL;
// 小さい入力の方が反復回数が稼げるので温度高めにした
let T = T0.powf(1.0 - t) * T1.powf(t) * 61.0 / input.N as f64;
if crt.len() > 0 {
// ランダムな中心(cx,cy)からランダムなマンハッタン距離wの範囲にある印を全削除
let NUM = (best_score * 1.2e-4).round() as u32;
let w = rng.gen_range(0, input.N as i32 / 6);
let cx = rng.gen_range(w, input.N as i32 - w);
let cy = rng.gen_range(w, input.N as i32 - w);
let num0 = (-w..=w)
.map(|dy| {
let w = w - dy.abs();
let lx = cx - w;
(crt_state.has_point[0][(cy + dy) as usize] >> lx << (64 - 2 * w - 1)).count_ones()
})
.sum::<u32>();
// 沢山消しすぎるとまともに再構築出来る確率が低い上に時間がかかるので選び直し
if num0 == 0 || num0 >= NUM {
continue;
}
let mut num = 0;
// 消した印を使う長方形も連鎖的に削除
for &rect in &crt {
let (x, y) = rect.0[0];
if (x - cx).abs() + (y - cy).abs() <= w
|| rect.0[1..]
.iter()
.any(|&(x, y)| is_deleted[x as usize * input.N + y as usize] == iter)
{
is_deleted[x as usize * input.N + y as usize] = iter;
num += 1;
if num >= NUM {
break;
}
}
}
if num == 0 || num >= NUM {
continue;
}
}
let deleted_rects = crt
.iter()
.filter(|r| is_deleted[r.0[0].0 as usize * input.N + r.0[0].1 as usize] == iter)
.cloned();
let mut state = crt_state.clone();
state.delete_rects(deleted_rects);
let ps1 = crt
.iter()
.filter(|rect| is_deleted[rect.0[0].0 as usize * input.N + rect.0[0].1 as usize] != iter)
.cloned()
.collect::<Vec<_>>();
state.init_cands(input.ps.iter().cloned().chain(ps1.iter().map(|r| r.0[0])));
// 部分的に削除した状態から、random playoutで解を再構築
let ps2 = state.playout(&mut rng);
// 序盤は重み1で最適化して時刻に応じて徐々に正規の重みに近づけている
let w1 = if t < t0 { t / t0 } else { 1.0 };
let crt_score =
normalized_score(crt_state.score, &input, S) * w1 + normalized_score(crt_state.score2, &input, S2) * (1.0 - w1);
let score = normalized_score(state.score, &input, S) * w1 + normalized_score(state.score2, &input, S2) * (1.0 - w1);
if best_score.setmax(normalized_score(state.score, &input, S)) {
best = ps1.clone().into_iter().chain(ps2.clone().into_iter()).collect();
eprintln!("{:.3}: {:.0}", get_time(), best_score);
}
if crt_score <= score || rng.gen_bool(((score - crt_score) as f64 / crt_score / T).exp()) {
crt_state = state;
crt = ps1.into_iter().chain(ps2.into_iter()).collect();
}
}
eprintln!("iter = {}", iter);
best
}
#[derive(Clone, Debug)]
struct State {
N: i32,
/// ある範囲に印が存在するかを高速に判定するため、ビットベクトルを用いて状態を表現。
/// (x,y)に印がある場合、以下のビットが1となる。
/// ```
/// has_point[0][y][x]
/// has_point[1][-x+y][(x+y)/2]
/// has_point[2][-x][y]
/// has_point[3][-x-y][(-x+y)/2]
/// ```
/// ただし、負のインデックスを回避するために-xはN-1-x、-yはN-1-yで置き換える。
has_point: [Vec<u64>; 4],
/// (x,y)に印があり、d方向に長方形の辺が伸びている場合にhas_edge[Nx+y]のdビット目が1となる。
has_edge: Vec<u8>,
/// 高速化のために、次に描画出来る長方形(と1点目から見た2点目の向き)の候補を保持しておく。
/// 新たな長方形を描画後に候補の追加のみで削除はしないため、不可能になったものも含まれており、実際に描画時に可能かを再度判定する。
/// 良い解では1x1の正方形を多用するため、1x1とそれ以外で区別して保持している。
cand: [Vec<Rect>; 2],
/// 正規の重みの和
score: i32,
/// 重み1の和(=印の個数)
score2: i32,
}
impl State {
fn new(input: &Input) -> Self {
let mut state = Self {
N: input.N as i32,
has_point: [
vec![0; input.N],
vec![0; input.N * 2 - 1],
vec![0; input.N],
vec![0; input.N * 2 - 1],
],
has_edge: vec![0; input.N * input.N],
cand: [vec![], vec![]],
score: 0,
score2: 0,
};
for &p in &input.ps {
state.insert_point(p);
}
state
}
fn on_board(&self, (x, y): P) -> bool {
0 <= x && x < self.N && 0 <= y && y < self.N
}
fn has_point(&self, (x, y): P) -> bool {
self.has_point[0][y as usize] >> x & 1 != 0
}
fn has_edge(&self, (x, y): P, mask: u8) -> bool {
self.has_edge[(x * self.N + y) as usize] & mask != 0
}
/// (x, y) に印を付けてスコアを更新
fn insert_point(&mut self, (x, y): P) {
let nx = self.N - 1 - x;
let ny = self.N - 1 - y;
self.has_point[0][y as usize] |= 1 << x;
self.has_point[1][(nx + y) as usize] |= 1 << ((x + y) / 2);
self.has_point[2][nx as usize] |= 1 << y;
self.has_point[3][(nx + ny) as usize] |= 1 << ((nx + y) / 2);
self.score += weight((x, y), self.N);
self.score2 += weight2((x, y), self.N);
}
fn insert_edge(&mut self, (x, y): P, mask: u8) {
self.has_edge[(x * self.N + y) as usize] |= mask;
}
/// (x, y) の印と辺を除去してスコアを更新
fn remove_point(&mut self, (x, y): P) {
let nx = self.N - 1 - x;
let ny = self.N - 1 - y;
self.has_point[0][y as usize] ^= 1 << x;
self.has_point[1][(nx + y) as usize] ^= 1 << ((x + y) / 2);
self.has_point[2][nx as usize] ^= 1 << y;
self.has_point[3][(nx + ny) as usize] ^= 1 << ((nx + y) / 2);
self.has_edge[(x * self.N + y) as usize] = 0;
self.score -= weight((x, y), self.N);
self.score2 -= weight2((x, y), self.N);
}
fn remove_edge(&mut self, (x, y): P, mask: u8) {
self.has_edge[(x * self.N + y) as usize] &= !mask;
}
/// 描画可能な長方形の候補を追加する。1x1の場合はtier0にそれ以外はtier1に保存される。
fn insert_cand(&mut self, (rect, d): Rect) {
let tier = if (rect[2].0 - rect[0].0).abs() + (rect[2].1 - rect[0].1).abs() == 2 {
0
} else {
1
};
self.cand[tier].push((rect, d));
}
/// (x, y) と (x2, y2) の間に他の点があるかを判定
fn has_point_in_range(&self, (x, y): P, (x2, y2): P, d: usize) -> bool {
let w = (x - x2).abs() + (y - y2).abs();
let nx = self.N - 1 - x;
let ny = self.N - 1 - y;
match d {
0 => w >= 2 && self.has_point[0][y as usize] >> (x + 1) << (65 - w) != 0,
1 => w >= 4 && self.has_point[1][(nx + y) as usize] >> ((x + y) / 2 + 1) << (65 - w / 2) != 0,
2 => w >= 2 && self.has_point[2][nx as usize] >> (y + 1) << (65 - w) != 0,
3 => w >= 4 && self.has_point[3][(nx + ny) as usize] >> ((nx + y) / 2 + 1) << (65 - w / 2) != 0,
4 => w >= 2 && self.has_point[0][y as usize] << (64 - x) >> (65 - w) != 0,
5 => w >= 4 && self.has_point[1][(nx + y) as usize] << (64 - (x + y) / 2) >> (65 - w / 2) != 0,
6 => w >= 2 && self.has_point[2][nx as usize] << (64 - y) >> (65 - w) != 0,
7 => w >= 4 && self.has_point[3][(nx + ny) as usize] << (64 - (nx + y) / 2) >> (65 - w / 2) != 0,
_ => unreachable!(),
}
}
/// pからd方向に進んだ最初の印(pは除く)の座標を返す
fn next_point(&self, (x, y): P, d: usize) -> Option<P> {
let nx = self.N - 1 - x;
let ny = self.N - 1 - y;
match d {
0 => {
let k = (self.has_point[0][y as usize] >> (x + 1)).trailing_zeros();
if k == 64 {
None
} else {
Some((x + 1 + k as i32, y))
}
}
1 => {
let k = (self.has_point[1][(nx + y) as usize] >> ((x + y) / 2 + 1)).trailing_zeros();
if k == 64 {
None
} else {
Some((x + 1 + k as i32, y + 1 + k as i32))
}
}
2 => {
let k = (self.has_point[2][nx as usize] >> (y + 1)).trailing_zeros();
if k == 64 {
None
} else {
Some((x, y + 1 + k as i32))
}
}
3 => {
let k = (self.has_point[3][(nx + ny) as usize] >> ((nx + y) / 2 + 1)).trailing_zeros();
if k == 64 {
None
} else {
Some((x - 1 - k as i32, y + 1 + k as i32))
}
}
4 => {
if x == 0 {
None
} else {
let k = (self.has_point[0][y as usize] << (64 - x)).leading_zeros();
if k == 64 {
None
} else {
Some((x - 1 - k as i32, y))
}
}
}
5 => {
if (x + y) / 2 == 0 {
None
} else {
let k = (self.has_point[1][(nx + y) as usize] << (64 - (x + y) / 2)).leading_zeros();
if k == 64 {
None
} else {
Some((x - 1 - k as i32, y - 1 - k as i32))
}
}
}
6 => {
if y == 0 {
None
} else {
let k = (self.has_point[2][nx as usize] << (64 - y)).leading_zeros();
if k == 64 {
None
} else {
Some((x, y - 1 - k as i32))
}
}
}
7 => {
if (nx + y) / 2 == 0 {
None
} else {
let k = (self.has_point[3][(nx + ny) as usize] << (64 - (nx + y) / 2)).leading_zeros();
if k == 64 {
None
} else {
Some((x + 1 + k as i32, y - 1 - k as i32))
}
}
}
_ => unreachable!(),
}
}
/// 長方形が描画可能か判定。
/// rect[0]の盤面内判定とrect[1~3]に印があるかの判定は既に済んでいるとしてここでは行っていない。
fn can_draw(&self, (rect, d): Rect) -> bool {
if self.has_point(rect[0]) {
return false;
}
for k in 0..4 {
let p = rect[k];
let q = rect[(k + 1) & 3];
let d = (d + 2 * k) & 7;
if self.has_edge(p, 1 << d | 1 << ((d + 2) & 7)) || self.has_point_in_range(p, q, d) {
return false;
}
}
true
}
/// 長方形を描画し、辺の情報を更新する
fn draw(&mut self, (rect, d): Rect) {
let p = rect[0];
self.insert_point(p);
// 既存の長方形の辺上に印を追加した場合に、その長方形の辺を追加
if let Some(q) = self.next_point(p, (d + 1) & 7) {
if self.has_edge(q, 1 << ((d + 5) & 7)) {
self.insert_edge(p, 1 << ((d + 1) & 7) | 1 << ((d + 5) & 7))
}
}
if let Some(q) = self.next_point(p, (d + 3) & 7) {
if self.has_edge(q, 1 << ((d + 7) & 7)) {
self.insert_edge(p, 1 << ((d + 3) & 7) | 1 << ((d + 7) & 7))
}
}
// 新たに描画する長方形の辺を追加
for k in 0..4 {
self.insert_edge(rect[k], 1 << ((d + k * 2) & 7) | 1 << ((d + k * 2 + 2) & 7));
}
}
/// 新たに追加する印が既に描画されている長方形の辺上に乗っているか判定
fn on_edge(&self, (rect, d): Rect) -> bool {
let p = rect[0];
if let Some(q) = self.next_point(p, (d + 1) & 7) {
if self.has_edge(q, 1 << ((d + 5) & 7)) {
return true;
}
}
if let Some(q) = self.next_point(p, (d + 3) & 7) {
if self.has_edge(q, 1 << ((d + 7) & 7)) {
return true;
}
}
false
}
fn check_and_insert_cand(&mut self, rect: Rect) {
if self.on_board(rect.0[0]) && self.can_draw(rect) {
self.insert_cand(rect);
}
}
/// 新たに印を付けた点pを用いることで描画可能となった長方形の候補を追加する
fn insert_new_cands(&mut self, p: P) {
let mut next = [None; 8];
for d in 0..8 {
if !self.has_edge(p, 1 << d) {
next[d] = self.next_point(p, d);
}
}
// 新たに追加した印を頂点とする長方形の候補を追加
for d in 0..8 {
if let Some(q) = next[d] {
if let Some(p2) = next[(d + 2) & 7] {
let p1 = (p2.0 + q.0 - p.0, p2.1 + q.1 - p.1);
self.check_and_insert_cand(([p1, p2, p, q], (d + 4) & 7));
}
if let Some(p4) = self.next_point(q, (d + 2) & 7) {
let p1 = (p.0 + p4.0 - q.0, p.1 + p4.1 - q.1);
self.check_and_insert_cand(([p1, p, q, p4], (d + 6) & 7));
}
if let Some(p2) = self.next_point(q, (d + 6) & 7) {
let p1 = (p.0 + p2.0 - q.0, p.1 + p2.1 - q.1);
self.check_and_insert_cand(([p1, p2, q, p], d));
}
}
}
}
/// 描画可能な長方形の候補を一から列挙する。
/// 印の集合は内部で保持していないので引数で渡す。
fn init_cands<PS: Iterator<Item = P>>(&mut self, ps: PS) {
for i in 0..self.cand.len() {
self.cand[i].clear();
}
let mut next = [None; 8];
for p3 in ps {
if self.has_edge[(p3.0 * self.N + p3.1) as usize] == 255 {
continue;
}
for d in 0..8 {
if !self.has_edge(p3, 1 << d) {
next[d] = self.next_point(p3, d);
} else {
next[d] = None;
}
}
for d in 0..8 {
if let (Some(p4), Some(p2)) = (next[d], next[(d + 2) & 7]) {
let p1 = (p2.0 + p4.0 - p3.0, p2.1 + p4.1 - p3.1);
if self.on_board(p1)
&& !self.has_point(p1)
&& !self.has_edge(p2, 1 << d)
&& !self.has_edge(p4, 1 << ((d + 2) & 7))
&& !self.has_point_in_range(p2, p1, d)
&& !self.has_point_in_range(p4, p1, (d + 2) & 7)
{
let rect = ([p1, p2, p3, p4], (d + 4) & 7);
self.insert_cand(rect);
}
}
}
}
}
/// 指定した長方形を除去する
fn delete_rects<RS: DoubleEndedIterator<Item = Rect>>(&mut self, deletes: RS) {
for (rect, d) in deletes.rev() {
for k in 0..4 {
self.remove_edge(rect[k], 1 << ((d + k * 2) & 7) | 1 << ((d + k * 2 + 2) & 7));
if self.has_point_in_range(rect[k], rect[(k + 1) & 3], (d + k * 2) & 7) {
let mut p = rect[k];
loop {
p = self.next_point(p, (d + k * 2) & 7).unwrap();
if p == rect[(k + 1) & 3] {
break;
}
self.remove_edge(p, 1 << ((d + k * 2) & 7) | 1 << ((d + k * 2 + 4) & 7));
}
}
}
self.remove_point(rect[0]);
}
}
/// 描画可能な長方形のうち、どれを次に描画するかの決定のための評価値を計算する。
fn eval(&self, (rect, d): Rect) -> i32 {
let mut score = 0;
for k in 0..4 {
// 長方形の各頂点について、180度逆側の2辺が既に描画されている場合、評価値+1
let p = rect[k];
let d = (d + 2 * k) & 7;
if self.has_edge(p, 1 << ((d + 4) & 7)) {
score += 1;
}
}
// 新たに追加する印が既に描画した辺上の場合、将来的な使用可能回数が2回分減るので評価値-2
if self.on_edge((rect, d)) {
score -= 2;
}
score
}
/// ランダムに最後までプレイする。
/// 1x1の正方形を優先して使用する。
fn playout(&mut self, rng: &mut Pcg64Mcg) -> Vec<Rect> {
let mut out = vec![];
let mut cand = vec![];
while self.cand[0].len() + self.cand[1].len() > 0 {
// 最初の一手は最小サイズを優先しない
let r = if out.len() == 0 {
if rng.gen_range(0, self.cand[0].len() + self.cand[1].len()) < self.cand[0].len() {
0
} else {
1
}
} else {
0
};
for tier in 0..self.cand.len() {
let tier = (tier + r) % self.cand.len();
// ランダムに最大4つ候補を取り出す
while self.cand[tier].len() > 0 && cand.len() < 4 {
let k = rng.gen_range(0, self.cand[tier].len());
let rect = self.cand[tier].swap_remove(k);
if self.can_draw(rect) {
cand.push(rect);
// 最初の一手は最初に取り出した候補で決定
if out.len() == 0 {
break;
}
}
}
if cand.len() > 0 {
// 評価値の一番高い候補を使用し、残りは戻す
let mut rect = cand.pop().unwrap();
let mut score = self.eval(rect);
while let Some(rect2) = cand.pop() {
if score.setmax(self.eval(rect2)) {
self.cand[tier].push(rect);
rect = rect2;
} else {
self.cand[tier].push(rect2);
}
}
out.push(rect);
self.draw(rect);
self.insert_new_cands(rect.0[0]);
break;
}
}
}
out
}
}
// 入出力と得点計算
// const DXY: [(i32, i32); 8] = [(1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1)];
fn weight((x, y): P, N: i32) -> i32 {
let dx = x - N / 2;
let dy = y - N / 2;
dx * dx + dy * dy + 1
}
#[allow(unused)]
fn weight2((x, y): P, N: i32) -> i32 {
1
}
fn normalized_score(score: i32, input: &Input, S: i32) -> f64 {
1e6 * input.N as f64 * input.N as f64 / input.ps.len() as f64 * score as f64 / S as f64
}
type P = (i32, i32);
/// 長方形の4頂点(反時計回り)と最初の辺の方向
type Rect = ([P; 4], usize);
type Output = Vec<Rect>;
#[derive(Clone, Debug)]
struct Input {
N: usize,
ps: Vec<P>,
}
fn read_input() -> Input {
input! {
N: usize, M: usize,
ps: [(i32, i32); M],
}
Input { N, ps }
}
fn write_output(out: &Output) {
println!("{}", out.len());
for rect in out {
for i in 0..4 {
print!("{} {}", rect.0[i].0, rect.0[i].1);
if i == 3 {
println!();
} else {
print!(" ");
}
}
}
}
// ここからライブラリ
pub trait SetMinMax {
fn setmin(&mut self, v: Self) -> bool;
fn setmax(&mut self, v: Self) -> bool;
}
impl<T> SetMinMax for T
where
T: PartialOrd,
{
fn setmin(&mut self, v: T) -> bool {
*self > v && {
*self = v;
true
}
}
fn setmax(&mut self, v: T) -> bool {
*self < v && {
*self = v;
true
}
}
}
#[macro_export]
macro_rules! mat {
($($e:expr),*) => { vec![$($e),*] };
($($e:expr,)*) => { vec![$($e),*] };
($e:expr; $d:expr) => { vec![$e; $d] };
($e:expr; $d:expr $(; $ds:expr)+) => { vec![mat![$e $(; $ds)*]; $d] };
}
pub fn get_time() -> f64 {
static mut STIME: f64 = -1.0;
let t = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap();
let ms = t.as_secs() as f64 + t.subsec_nanos() as f64 * 1e-9;
unsafe {
if STIME < 0.0 {
STIME = ms;
}
// ローカル環境とジャッジ環境の実行速度差はget_timeで吸収しておくと便利
#[cfg(feature = "local")]
{
(ms - STIME) * 1.5
}
#[cfg(not(feature = "local"))]
{
(ms - STIME)
}
}
}
Submission Info
| Submission Time |
|
| Task |
A - RectJoin |
| User |
wata_admin |
| Language |
Rust (1.42.0) |
| Score |
79911186 |
| Code Size |
24397 Byte |
| Status |
AC |
| Exec Time |
4908 ms |
| Memory |
3876 KiB |
Compile Error
warning: unnecessary parentheses around block return value
--> src/main.rs:621:13
|
621 | (ms - STIME)
| ^^^^^^^^^^^^ help: remove these parentheses
|
= note: `#[warn(unused_parens)]` on by default
Judge Result
| Set Name |
test_ALL |
| Score / Max Score |
79911186 / 5000000000 |
| Status |
|
| Set Name |
Test Cases |
| test_ALL |
test_0000.txt, test_0001.txt, test_0002.txt, test_0003.txt, test_0004.txt, test_0005.txt, test_0006.txt, test_0007.txt, test_0008.txt, test_0009.txt, test_0010.txt, test_0011.txt, test_0012.txt, test_0013.txt, test_0014.txt, test_0015.txt, test_0016.txt, test_0017.txt, test_0018.txt, test_0019.txt, test_0020.txt, test_0021.txt, test_0022.txt, test_0023.txt, test_0024.txt, test_0025.txt, test_0026.txt, test_0027.txt, test_0028.txt, test_0029.txt, test_0030.txt, test_0031.txt, test_0032.txt, test_0033.txt, test_0034.txt, test_0035.txt, test_0036.txt, test_0037.txt, test_0038.txt, test_0039.txt, test_0040.txt, test_0041.txt, test_0042.txt, test_0043.txt, test_0044.txt, test_0045.txt, test_0046.txt, test_0047.txt, test_0048.txt, test_0049.txt |
| Case Name |
Status |
Exec Time |
Memory |
| test_0000.txt |
AC |
4908 ms |
3164 KiB |
| test_0001.txt |
AC |
4902 ms |
3240 KiB |
| test_0002.txt |
AC |
4902 ms |
3032 KiB |
| test_0003.txt |
AC |
4903 ms |
3220 KiB |
| test_0004.txt |
AC |
4902 ms |
3308 KiB |
| test_0005.txt |
AC |
4902 ms |
3216 KiB |
| test_0006.txt |
AC |
4902 ms |
3036 KiB |
| test_0007.txt |
AC |
4905 ms |
3696 KiB |
| test_0008.txt |
AC |
4902 ms |
3000 KiB |
| test_0009.txt |
AC |
4902 ms |
3012 KiB |
| test_0010.txt |
AC |
4905 ms |
3752 KiB |
| test_0011.txt |
AC |
4902 ms |
3304 KiB |
| test_0012.txt |
AC |
4904 ms |
3496 KiB |
| test_0013.txt |
AC |
4903 ms |
3492 KiB |
| test_0014.txt |
AC |
4904 ms |
3416 KiB |
| test_0015.txt |
AC |
4902 ms |
3060 KiB |
| test_0016.txt |
AC |
4905 ms |
3604 KiB |
| test_0017.txt |
AC |
4903 ms |
3408 KiB |
| test_0018.txt |
AC |
4903 ms |
3464 KiB |
| test_0019.txt |
AC |
4902 ms |
3324 KiB |
| test_0020.txt |
AC |
4902 ms |
3324 KiB |
| test_0021.txt |
AC |
4904 ms |
3444 KiB |
| test_0022.txt |
AC |
4902 ms |
3160 KiB |
| test_0023.txt |
AC |
4905 ms |
3876 KiB |
| test_0024.txt |
AC |
4902 ms |
3224 KiB |
| test_0025.txt |
AC |
4902 ms |
3104 KiB |
| test_0026.txt |
AC |
4903 ms |
3232 KiB |
| test_0027.txt |
AC |
4904 ms |
3624 KiB |
| test_0028.txt |
AC |
4904 ms |
3588 KiB |
| test_0029.txt |
AC |
4904 ms |
3580 KiB |
| test_0030.txt |
AC |
4903 ms |
3540 KiB |
| test_0031.txt |
AC |
4903 ms |
3492 KiB |
| test_0032.txt |
AC |
4904 ms |
3344 KiB |
| test_0033.txt |
AC |
4904 ms |
3504 KiB |
| test_0034.txt |
AC |
4903 ms |
3188 KiB |
| test_0035.txt |
AC |
4905 ms |
3616 KiB |
| test_0036.txt |
AC |
4903 ms |
3580 KiB |
| test_0037.txt |
AC |
4903 ms |
3268 KiB |
| test_0038.txt |
AC |
4904 ms |
3452 KiB |
| test_0039.txt |
AC |
4902 ms |
3192 KiB |
| test_0040.txt |
AC |
4902 ms |
3064 KiB |
| test_0041.txt |
AC |
4901 ms |
3052 KiB |
| test_0042.txt |
AC |
4902 ms |
3212 KiB |
| test_0043.txt |
AC |
4903 ms |
3420 KiB |
| test_0044.txt |
AC |
4902 ms |
3116 KiB |
| test_0045.txt |
AC |
4903 ms |
3224 KiB |
| test_0046.txt |
AC |
4903 ms |
3304 KiB |
| test_0047.txt |
AC |
4903 ms |
3088 KiB |
| test_0048.txt |
AC |
4904 ms |
3660 KiB |
| test_0049.txt |
AC |
4902 ms |
3196 KiB |