結果
| 問題 |
No.2858 Make a Palindrome
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2024-08-28 15:23:30 |
| 言語 | D (dmd 2.109.1) |
| 結果 |
AC
|
| 実行時間 | 485 ms / 3,000 ms |
| コード長 | 3,057 bytes |
| コンパイル時間 | 2,111 ms |
| コンパイル使用メモリ | 173,356 KB |
| 実行使用メモリ | 17,588 KB |
| 最終ジャッジ日時 | 2024-08-28 15:23:45 |
| 合計ジャッジ時間 | 10,812 ms |
|
ジャッジサーバーID (参考情報) |
judge2 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 40 |
ソースコード
import std;
void main () {
int T = readln.chomp.to!int;
foreach (i; 0..T) {
int N, M; readln.read(N, M);
string S = readln.chomp;
solve(N, M, S);
}
}
void solve (int N, int M, string S) {
// Sが回文でない時を考える。
// Sを連結した文字列の連続部分列が回文であるとき、Sをまるまる含むかどうかがカギになる。
// Sをまるまる含む場合、Sは必ずちょうど二つの回文に分解できる。
// S三つの最長回文を求めて、2|S|を超えている場合、必ず実現できる。(さっきの議論により、二つの回文に分解できるので、これをつなげる感じで伸ばせる)
// そうでない場合、Mの値によっては実現できる可能性がある。
// ローリングハッシュ + 二分探索しか思いつかないので、Manacher's algorithmをパクって実装する。
// 窃盗: https://snuke.hatenablog.com/entry/2014/12/02/235837
auto R = new int[](0);
void snuke_manacher (string S) {
R.length = S.length;
int i = 0, j = 0;
while (i < S.length) {
while (i-j >= 0 && i+j < S.length && S[i-j] == S[i+j]) ++j;
R[i] = j;
int k = 1;
while (i-k >= 0 && k+R[i-k] < j) R[i+k] = R[i-k], ++k;
i += k; j -= k;
}
}
{ // S
string T = "_";
foreach (c; S) {
T ~= c;
T ~= "_";
}
snuke_manacher(T);
foreach (i; 0..R.length) {
int len = (R[i] - 1) / 2 * 2;
if (i % 2 == 1) len++;
if (M <= len) {
writeln(1);
return;
}
}
}
{ // SS
string T = "_";
foreach (c; S) {
T ~= c;
T ~= "_";
}
foreach (c; S) {
T ~= c;
T ~= "_";
}
snuke_manacher(T);
foreach (i; 0..R.length) {
int len = (R[i] - 1) / 2 * 2;
if (i % 2 == 1) len++;
if (M <= len) {
writeln(2);
return;
}
}
}
{ // SSS
string T = "_";
foreach (c; S) {
T ~= c;
T ~= "_";
}
foreach (c; S) {
T ~= c;
T ~= "_";
}
foreach (c; S) {
T ~= c;
T ~= "_";
}
int maximum = 0;
snuke_manacher(T);
foreach (i; 0..R.length) {
int len = (R[i] - 1) / 2 * 2;
if (i % 2 == 1) len++;
maximum = max(maximum, len);
}
if (2 * N <= maximum) {
int rem = 3 * N - maximum;
writeln((M + rem + N - 1) / N);
return;
}
}
writeln(-1);
}
void read (T...) (string S, ref T args) {
import std.conv : to;
import std.array : split;
auto buf = S.split;
foreach (i, ref arg; args) {
arg = buf[i].to!(typeof(arg));
}
}