AtCoder Grand Contest 008 D - K-th K
http://agc008.contest.atcoder.jp/tasks/agc008_d
問題概要
与えられた長さNの数列Xに対して、次の条件すべてを満たす数列Aが構成できるか判定せよ。またできるならば実際にひとつ示せ。
- 条件1. Aの長さはN2
- 条件2. Aは要素として1, 2, …, NをN個ずつ含む
- 条件3. 各i (1 <= i <= N) について、Aにおいて整数iのうち左からi番目に位置するものは、A全体ではX[i]番目に位置する
解法
とりあえずX[i]をiで埋める。各iについてX[i]より前に何個置いてX[i]より後ろに何個置けばいいかは決まっているので、あとは前から見ていってX[i]が小さい順にiを詰めていけばよい。
感想
罠があると思ったらなかった
コード (D言語)
import std.stdio, std.array, std.string, std.conv, std.algorithm; import std.typecons, std.range, std.random, std.math, std.container; import std.numeric, std.bigint, core.bitop; void main() { auto N = readln.chomp.to!int; auto A = readln.split.map!(to!int).array; auto ans = new int[](N*N); foreach (i; 0..N) ans[A[i] - 1] = i + 1; auto front = N.iota.array; auto back = N.iota.map!(i => N - i - 1).array; auto pq1 = new BinaryHeap!(Array!(Tuple!(int, int)), "a[0] > b[0]"); auto pq2 = new BinaryHeap!(Array!(Tuple!(int, int)), "a[0] > b[0]"); foreach (i; 1..N) pq1.insert(tuple(A[i] - 1, i + 1)); pq2.insert(tuple(A[0] - 1, 1)); foreach (i; 0..N*N) { if (ans[i] > 0) { continue; } else if (!pq1.empty) { auto t = pq1.front; auto pos = t[0]; auto num = t[1]; if (pos < i) { writeln("No"); return; } ans[i] = num; front[num-1] -= 1; if (front[num-1] == 0) { pq1.removeFront; if (num != N) pq2.insert(tuple(pos, num)); } } else if (!pq2.empty) { auto t = pq2.front; auto pos = t[0]; auto num = t[1]; if (pos > i) { writeln("No"); return; } ans[i] = num; back[num-1] -= 1; if (back[num-1] == 0) pq2.removeFront; } else { writeln("No"); return; } } writeln("Yes"); ans.map!(a => a.to!string).join(" ").writeln; }