Submission #4032098
Source Code Expand
#[allow(unused_imports)]
use std::cmp::*;
#[allow(unused_imports)]
use std::collections::*;
use std::io::{Write, BufWriter};
// https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8
macro_rules! input {
($($r:tt)*) => {
let stdin = std::io::stdin();
let mut bytes = std::io::Read::bytes(std::io::BufReader::new(stdin.lock()));
let mut next = move || -> String{
bytes
.by_ref()
.map(|r|r.unwrap() as char)
.skip_while(|c|c.is_whitespace())
.take_while(|c|!c.is_whitespace())
.collect()
};
input_inner!{next, $($r)*}
};
}
macro_rules! input_inner {
($next:expr) => {};
($next:expr, ) => {};
($next:expr, $var:ident : $t:tt $($r:tt)*) => {
let $var = read_value!($next, $t);
input_inner!{$next $($r)*}
};
}
macro_rules! read_value {
($next:expr, ( $($t:tt),* )) => {
( $(read_value!($next, $t)),* )
};
($next:expr, [ $t:tt ; $len:expr ]) => {
(0..$len).map(|_| read_value!($next, $t)).collect::<Vec<_>>()
};
($next:expr, chars) => {
read_value!($next, String).chars().collect::<Vec<char>>()
};
($next:expr, usize1) => {
read_value!($next, usize) - 1
};
($next:expr, [ $t:tt ]) => {{
let len = read_value!($next, usize);
(0..len).map(|_| read_value!($next, $t)).collect::<Vec<_>>()
}};
($next:expr, $t:ty) => {
$next().parse::<$t>().expect("Parse error")
};
}
// This solution is written after the author read the editorial.
/*
* Z algorithm. Calculates an array a[i] = |lcp(s, s[i...|s|])|,
* where s is the given string.
* If n = s.length(), the returned array has length n + 1.
* E.g. z_algorithm("ababa") = {5, 0, 3, 0, 1, 0}
* Reference: http://snuke.hatenablog.com/entry/2014/12/03/214243
* Verified by: AtCoder ARC055-C (http://arc055.contest.atcoder.jp/submissions/1061771)
*/
fn z_algorithm<T: PartialEq>(s: &[T]) -> Vec<usize> {
let n = s.len();
let mut ret = vec![0; n + 1];
ret[0] = n;
let mut i = 1; let mut j = 0;
while i < n {
while i + j < n && s[j] == s[i + j] { j += 1; }
ret[i] = j;
if j == 0 { i += 1; continue; }
let mut k = 1;
while i + k < n && k + ret[k] < j {
ret[i + k] = ret[k];
k += 1;
}
i += k; j -= k;
}
ret
}
fn calc_poss(s: &[Vec<char>], k: usize) -> Vec<Vec<bool>> {
let n = s.len();
let mut poss = vec![vec![false; k + 1]; n + 1];
poss[n][0] = true;
for i in (0 .. n).rev() {
let len = s[i].len();
for j in 0 .. k - len + 1 {
poss[i][j + len] |= poss[i + 1][j];
}
for j in 0 .. k + 1 {
poss[i][j] |= poss[i + 1][j];
}
}
poss
}
fn solve() {
use std::cmp::Ordering::*;
let out = std::io::stdout();
let mut out = BufWriter::new(out.lock());
macro_rules! puts {
($($format:tt)*) => (write!(out,$($format)*).unwrap());
}
input! {
n: usize,
k: usize,
s: [chars; n],
}
let poss = calc_poss(&s, k);
let mut cs = vec![Vec::new(); n + 1];
let mut dp = vec![vec![false; k + 1]; n + 1];
dp[0][0] = true;
for i in 0 .. n {
let len = s[i].len();
let mut css = s[i].clone();
css.extend_from_slice(&cs[i]);
let zarr = z_algorithm(&css);
// cs[i + 1] is implicitly represented by
// cs[i][..cs_len] + if s_appended { s[i] } else { "" },
// where (cs_len, s_appended) = cs_next.
let mut cs_next = (0, false);
// compares css[a .. a + blen] and css[b .. b + blen].
// Returns (comparison, is_prefix).
// If one is a prefix of the other, the longer one is smaller.
// Either a or b must be 0.
let cmp_slice = |a: usize, alen: usize, b: usize, blen: usize| {
let common_len = match (a, b) {
(0, _) => zarr[b],
(_, 0) => zarr[a],
_ => unreachable!(),
};
if min(alen, blen) <= common_len {
(blen.cmp(&alen), true) // longer is smaller
} else {
(css[a + common_len].cmp(&css[b + common_len]), false)
}
};
// Compares cs[i][..j] + (if fappend { s[i] } else { "" }) and the current cs[i + 1].
// If one is a prefix of the other, the longer one wins (is smaller).
let cmps = |(j, fappend): (usize, bool),
(cs_len, s_appended): (usize, bool)| {
match (fappend, s_appended) {
(true, true) if j == cs_len => (Equal, true),
(true, true) if j > cs_len + len =>
cmp_slice(len + cs_len, j - cs_len, 0, len),
(true, true) if cs_len > j + len =>
cmp_slice(0, len, len + j, cs_len - j),
(true, true) if j > cs_len => {
let res = cmp_slice(len + cs_len, j - cs_len, 0, j - cs_len);
if res.0 != Equal { return res }
cmp_slice(0, len, j - cs_len, len - (j - cs_len))
},
(true, true) if cs_len > j => {
let res = cmp_slice(0, cs_len - j, len + j, cs_len - j);
if res.0 != Equal { return res }
cmp_slice(cs_len - j, len - (cs_len - j), 0, len)
},
(true, true) => unreachable!(),
(true, false) if cs_len <= j => (Less, true),
(true, false) => cmp_slice(0, len, len + j, cs_len - j),
(false, true) if j <= cs_len => (Greater, true),
(false, true) => cmp_slice(len + cs_len, j - cs_len, 0, len),
(false, false) => (cs_len.cmp(&j), true),
}
};
// get min
for j in 0 .. k + 1 {
if !poss[i + 1][k - j] || !dp[i][j] { continue; }
if cmps((j, false), cs_next).0 == Less {
cs_next = (j, false);
}
}
for j in 0 .. k - len + 1 {
if !poss[i + 1][k - j - len] || !dp[i][j] { continue; }
if cmps((j, true), cs_next).0 == Less {
cs_next = (j, true);
}
}
// update dp
for j in 0 .. k + 1 {
if !poss[i + 1][k - j] || !dp[i][j] { continue; }
dp[i + 1][j] |= cmps((j, false), cs_next).1;
}
for j in 0 .. k - len + 1 {
if !poss[i + 1][k - j - len] || !dp[i][j] { continue; }
dp[i + 1][j + len] |= cmps((j, true), cs_next).1;
}
cs[i + 1] = cs[i][..cs_next.0].to_vec();
if cs_next.1 {
cs[i + 1].extend_from_slice(&s[i]);
}
}
puts!("{}\n", cs[n][..k].iter().cloned().collect::<String>());
}
fn main() {
// In order to avoid potential stack overflow, spawn a new thread.
let stack_size = 104_857_600; // 100 MB
let thd = std::thread::Builder::new().stack_size(stack_size);
thd.spawn(|| solve()).unwrap().join().unwrap();
}
Submission Info
| Submission Time |
|
| Task |
F - Iroha Loves Strings |
| User |
kobae964 |
| Language |
Rust (1.15.1) |
| Score |
1500 |
| Code Size |
7140 Byte |
| Status |
AC |
| Exec Time |
952 ms |
| Memory |
156028 KiB |
Judge Result
| Set Name |
Sample |
All |
| Score / Max Score |
0 / 0 |
1500 / 1500 |
| Status |
|
|
| Set Name |
Test Cases |
| Sample |
0_sample01, 0_sample02, 0_sample03 |
| All |
0_sample01, 0_sample02, 0_sample03, abab0, abten0, allsame0, allsame_ex0, bigrand0, bigrand1, firstlast0, firstlast1, fullrand0, fullrand1, fullrand2, kaidan0, maxrand0, maxrand1, maxrand2, roll_hyper0, roll_hyper1, roll_hyper_r0, rolling0, rolling1, smallc0, smallc1, smallrand0, smallrand1, smallrand2, zzza0 |
| Case Name |
Status |
Exec Time |
Memory |
| 0_sample01 |
AC |
3 ms |
8572 KiB |
| 0_sample02 |
AC |
3 ms |
8572 KiB |
| 0_sample03 |
AC |
3 ms |
8572 KiB |
| abab0 |
AC |
406 ms |
76028 KiB |
| abten0 |
AC |
350 ms |
147836 KiB |
| allsame0 |
AC |
952 ms |
156028 KiB |
| allsame_ex0 |
AC |
949 ms |
145788 KiB |
| bigrand0 |
AC |
157 ms |
51452 KiB |
| bigrand1 |
AC |
245 ms |
67964 KiB |
| firstlast0 |
AC |
301 ms |
80252 KiB |
| firstlast1 |
AC |
303 ms |
84348 KiB |
| fullrand0 |
AC |
176 ms |
63740 KiB |
| fullrand1 |
AC |
270 ms |
84348 KiB |
| fullrand2 |
AC |
232 ms |
71932 KiB |
| kaidan0 |
AC |
748 ms |
143740 KiB |
| maxrand0 |
AC |
237 ms |
63740 KiB |
| maxrand1 |
AC |
257 ms |
70012 KiB |
| maxrand2 |
AC |
265 ms |
72060 KiB |
| roll_hyper0 |
AC |
377 ms |
147836 KiB |
| roll_hyper1 |
AC |
374 ms |
147836 KiB |
| roll_hyper_r0 |
AC |
377 ms |
147836 KiB |
| rolling0 |
AC |
376 ms |
147836 KiB |
| rolling1 |
AC |
376 ms |
149884 KiB |
| smallc0 |
AC |
69 ms |
30972 KiB |
| smallc1 |
AC |
72 ms |
30972 KiB |
| smallrand0 |
AC |
3 ms |
8572 KiB |
| smallrand1 |
AC |
4 ms |
8572 KiB |
| smallrand2 |
AC |
4 ms |
8572 KiB |
| zzza0 |
AC |
209 ms |
78076 KiB |