Submission #34066894
Source Code Expand
void main() { runSolver(); }
// ----------------------------------------------
enum MAX_N = 50;
enum DIRS = zip([-1, 0, 1, 0], [0, -1, 0, 1]).array;
struct Point {
int x, y;
T of(T)(T[][] t) { return t[x][y]; }
bool valid(int border) { return min(x, y) >= 0 && max(x, y) < border; }
int toId() { return MAX_N * x + y; }
}
struct Connection {
int sx, sy, ex, ey;
this(int sx, int sy, int ex, int ey) {
this.sx = sx;
this.sy = sy;
this.ex = ex;
this.ey = ey;
}
this(Point f, Point t) {
this(f.x, f.y, t.x, t.y);
}
string toString() {
return "%s %s %s %s".format(sx, sy, ex, ey);
}
}
struct Move {
int sx, sy, ex, ey;
this(int sx, int sy, int ex, int ey) {
this.sx = sx;
this.sy = sy;
this.ex = ex;
this.ey = ey;
}
this(Point f, Point t) {
this(f.x, f.y, t.x, t.y);
}
string toString() {
return "%s %s %s %s".format(sx, sy, ex, ey);
}
}
int calcScore(UnionFind uf, int[] penalty) {
auto n = MAX_N * MAX_N;
auto sizes = new int[](n);
foreach(i; 0..n) sizes[i] -= penalty[i];
foreach(x; 0..MAX_N) foreach(y; 0..MAX_N) {
sizes[uf.root(MAX_N * x + y)]++;
}
return n.iota.map!(i => sizes[i]*(sizes[i] - 1) / 2 - penalty[i] * sizes[i]).sum;
}
void problem() {
auto StartTime = MonoTime.currTime();
auto N = scan!int;
auto K = scan!int;
auto G = scan!string(N).map!(s => s.map!(c => (c - '0').to!int).array).array;
bool elapsed(int ms) {
return (ms <= (MonoTime.currTime() - StartTime).total!"msecs");
}
int calcSimpleScore(int[][] g) {
int ret;
auto visited = new bool[][](N, N);
auto uf = UnionFind(MAX_N * MAX_N);
foreach(x; 0..N) foreach(y; 0..N) {
if (visited[x][y]) continue;
auto k = g[x][y];
if (k == 0 || visited[x][y]) continue;
visited[x][y] = true;
int size = 1;
for(auto queue = new DList!Point(Point(x, y)); !queue.empty;) {
auto p = queue.front;
queue.removeFront;
foreach(dir; DIRS) {
foreach(delta; 1..N) {
auto np = p;
np.x += dir[0] * delta;
np.y += dir[1] * delta;
if (!np.valid(N)) break;
if (np.of(G) == k) {
if (uf.same(p.toId, np.toId)) break;
queue.insertBack(np);
uf.unite(p.toId, np.toId);
size++;
foreach(d; 1..delta + 1) {
auto dp = p;
dp.x += dir[0] * d;
dp.y += dir[1] * d;
visited[dp.x][dp.y] = true;
}
break;
}
if (np.of(G) == 0) if (np.of(visited)) break; else continue;
if (np.of(G) != k) break;
}
}
}
ret += size * (size - 1) / 2;
}
return ret;
}
Move[] executeSortingMove() {
Move[] moves;
foreach(k; 1..K + 1) {
auto perX = new int[][](N, 0);
foreach(x; 0..N) foreach(y; 0..N) {
if (G[x][y] == k) perX[x] ~= y;
}
foreach(x, arr; perX.enumerate(0).array.sort!"a[1].length < b[1].length") {
long up = x == 0 ? -1 : perX[x - 1].length;
long down = x == N - 1 ? -1 : perX[x + 1].length;
if (up < arr.length && down < arr.length) break;
foreach(y; arr) {
if (up >= down && G[x - 1][y] == 0) {
moves ~= Move(x, y, x-1, y);
swap(G[x][y], G[x - 1][y]);
} else if (x < N - 1 && G[x + 1][y] == 0) {
moves ~= Move(x, y, x+1, y);
swap(G[x][y], G[x + 1][y]);
}
}
}
auto perY = new int[][](N, 0);
foreach(x; 0..N) foreach(y; 0..N) {
if (G[x][y] == k) perY[y] ~= x;
}
foreach(y, arr; perY.enumerate(0).array.sort!"a[1].length < b[1].length") {
long up = y == 0 ? -1 : perY[y - 1].length;
long down = y == N - 1 ? -1 : perY[y + 1].length;
if (up < arr.length && down < arr.length) break;
foreach(x; arr) {
if (up >= down && G[x][y - 1] == 0) {
moves ~= Move(x, y, x, y - 1);
swap(G[x][y], G[x][y - 1]);
} else if (y < N - 1 && G[x][y + 1] == 0) {
moves ~= Move(x, y, x, y + 1);
swap(G[x][y], G[x][y + 1]);
}
}
}
}
return moves;
}
Move[][] executeRandomMove() {
Move[][] moves;
int rest = K * 100;
// if (G.map!(g => g.count(0)).sum > N*N / 10) return moves;
foreach(_; 0..1000) {
if (rest <= K*50) break;
if (elapsed(2000)) break;
Point[] whites;
foreach(x; 0..N) foreach(y; 0..N) {
if (G[x][y] == 0) whites ~= Point(x, y);
}
int maxScore;
Move[] maxMoves;
DList!Move ml;
void dfs(Point p, Point pre, int t) {
if (maxScore.chmax(calcSimpleScore(G))) maxMoves = ml.array;
if (t == 0) return;
static foreach(d; DIRS) {{
auto np = Point(p.x + d[0], p.y + d[1]);
if (np.valid(N) && np != pre && np.of(G) != 0) {
ml.insertBack(Move(np, p));
swap(G[p.x][p.y], G[np.x][np.y]);
dfs(np, p, t - 1);
swap(G[p.x][p.y], G[np.x][np.y]);
ml.removeBack;
}
}}
}
foreach(p; whites.randomShuffle[0..min(120, $)]) {
dfs(p, p, 3);
}
if (calcSimpleScore(G) < maxScore) {
rest -= maxMoves.length;
moves ~= maxMoves;
foreach(mm; maxMoves) swap(G[mm.sx][mm.sy], G[mm.ex][mm.ey]);
// maxScore.deb;
} else {
break;
}
}
return moves;
}
auto solve() {
auto init = G.map!"a.dup".array;
auto randomMoves = executeRandomMove();
// if (moves.empty) moves ~= executeSortingMove();
Move[] bestMoves;
Connection[] bestConnections;
int bestScore;
foreach(moveIgnores; 0..10) {
Move[] moves;
G = init.map!"a.dup".array;
foreach(mm; randomMoves[0..max(0, $ - moveIgnores)]) {
foreach(m; mm) swap(G[m.sx][m.sy], G[m.ex][m.ey]);
moves ~= mm;
}
Connection[] connections;
auto globalVisited = new bool[][](N, N);
auto globalUf = UnionFind(MAX_N * MAX_N);
int rest = K*100 - moves.length.to!int;
auto penalty = new int[](MAX_N * MAX_N);
while(rest > 0) {
int bestSize;
Point bestPoint;
Point[Point] bestWalls;
foreach(x; 0..N) foreach(y; 0..N) {
if (G[x][y] == 0 || globalVisited[x][y]) continue;
Point[Point] walls;
auto k = G[x][y];
auto visited = globalVisited.map!"a.dup".array;
auto uf = globalUf.dup;
int size;
for(auto queue = new DList!Point(Point(x, y)); !queue.empty;) {
auto p = queue.front;
queue.removeFront;
foreach(dir; zip([-1, 0, 1, 0], [0, -1, 0, 1])) {
foreach(delta; 1..N) {
auto np = p;
np.x += dir[0] * delta;
np.y += dir[1] * delta;
if (!np.valid(N)) break;
if (np.of(G) == k) {
if (uf.same(p.toId, np.toId)) break;
if (rest <= 0) break;
queue.insertBack(np);
uf.unite(p.toId, np.toId);
size++;
foreach(d; 1..delta + 1) {
auto dp = p;
dp.x += dir[0] * d;
dp.y += dir[1] * d;
visited[dp.x][dp.y] = true;
}
break;
}
if (np.of(G) == 0) if (np.of(visited)) break; else continue;
if (np.of(G) != k) {
if (!np.of(visited)) walls[np] = p;
break;
}
}
}
}
if (bestSize.chmax(size)) {
bestPoint = Point(x, y);
bestWalls = walls;
}
}
if (bestSize <= 1) break;
auto k = bestPoint.of(G);
int bestWallSize;
Point bestWall;
foreach(w; bestWalls.keys) {
auto bk = G[w.x][w.y];
G[w.x][w.y] = k;
auto visited = globalVisited.map!"a.dup".array;
auto uf = globalUf.dup;
int wallSize;
for(auto queue = new DList!Point(bestPoint); !queue.empty;) {
auto p = queue.front;
queue.removeFront;
foreach(dir; zip([-1, 0, 1, 0], [0, -1, 0, 1])) {
foreach(delta; 1..N) {
auto np = p;
np.x += dir[0] * delta;
np.y += dir[1] * delta;
if (!np.valid(N)) break;
if (np.of(G) == k) {
if (uf.same(p.toId, np.toId)) break;
queue.insertBack(np);
uf.unite(p.toId, np.toId);
wallSize++;
foreach(d; 1..delta + 1) {
auto dp = p;
dp.x += dir[0] * d;
dp.y += dir[1] * d;
visited[dp.x][dp.y] = true;
}
break;
}
if (np.of(G) == 0) if (np.of(visited)) break; else continue;
if (np.of(G) != k) break;
}
}
}
if (bestWallSize.chmax(wallSize)) bestWall = w;
G[w.x][w.y] = bk;
}
if (bestWallSize > bestSize + 3) {
// [bestPoint, bestWall].deb;
// bestWall.of(globalVisited).deb;
G[bestWall.x][bestWall.y] = k;
globalVisited[bestWall.x][bestWall.y] = true;
} else bestWallSize = 0;
globalVisited[bestPoint.x][bestPoint.y] = true;
for(auto queue = new DList!Point(bestPoint); !queue.empty;) {
auto p = queue.front;
queue.removeFront;
foreach(dir; zip([-1, 0, 1, 0], [0, -1, 0, 1])) {
foreach(delta; 1..N) {
auto np = p;
np.x += dir[0] * delta;
np.y += dir[1] * delta;
if (!np.valid(N)) break;
if (np.of(G) == k) {
if (globalUf.same(p.toId, np.toId)) break;
if (rest <= 0) break;
queue.insertBack(np);
globalUf.unite(p.toId, np.toId);
connections ~= Connection(p, np);
rest--;
foreach(d; 1..delta + 1) {
auto dp = p;
dp.x += dir[0] * d;
dp.y += dir[1] * d;
globalVisited[dp.x][dp.y] = true;
}
break;
}
if (np.of(G) == 0) if (np.of(globalVisited)) break; else continue;
if (np.of(G) != k) break;
}
}
}
if (bestWallSize > 0) penalty[globalUf.root(bestPoint.toId)]++;
}
if (bestScore.chmax(calcScore(globalUf, penalty))) {
bestConnections = connections;
bestMoves = moves;
}
if (elapsed(2750)) break;
}
bestMoves.length.writeln;
bestMoves.each!writeln;
bestConnections.length.writeln;
bestConnections.each!writeln;
stderr.writeln(bestScore);
}
outputForAtCoder(&solve);
}
// ----------------------------------------------
import std;
string scan(){ static string[] ss; while(!ss.length) ss = readln.chomp.split; string res = ss[0]; ss.popFront; return res; }
T scan(T)(){ return scan.to!T; }
T[] scan(T)(long n){ return n.iota.map!(i => scan!T()).array; }
void deb(T ...)(T t){ debug { write("#"); writeln(t); }}
T[] divisors(T)(T n) { T[] ret; for (T i = 1; i * i <= n; i++) { if (n % i == 0) { ret ~= i; if (i * i != n) ret ~= n / i; } } return ret.sort.array; }
bool chmin(T)(ref T a, T b) { if (b < a) { a = b; return true; } else return false; }
bool chmax(T)(ref T a, T b) { if (b > a) { a = b; return true; } else return false; }
string charSort(alias S = "a < b")(string s) { return (cast(char[])((cast(byte[])s).sort!S.array)).to!string; }
ulong comb(ulong a, ulong b) { if (b == 0) {return 1;}else{return comb(a - 1, b - 1) * a / b;}}
string toAnswerString(R)(R r) { return r.map!"a.to!string".joiner(" ").array.to!string; }
void outputForAtCoder(T)(T delegate() fn) {
static if (is(T == float) || is(T == double) || is(T == real)) "%.16f".writefln(fn());
else static if (is(T == void)) fn();
else static if (is(T == string)) fn().writeln;
else static if (isInputRange!T) {
static if (!is(string == ElementType!T) && isInputRange!(ElementType!T)) foreach(r; fn()) r.toAnswerString.writeln;
else foreach(r; fn()) r.writeln;
}
else fn().writeln;
}
void runSolver() {
static import std.datetime.stopwatch;
enum BORDER = "#==================================";
debug { BORDER.writeln; while(!stdin.eof) { "<<< Process time: %s >>>".writefln(std.datetime.stopwatch.benchmark!problem(1)); BORDER.writeln; } }
else problem();
}
enum YESNO = [true: "Yes", false: "No"];
// -----------------------------------------------
struct UnionFind {
int[] parent;
int[] option;
this(int size) {
parent.length = size;
option.length = size;
foreach(i; 0..size) parent[i] = i;
}
int root(int x) {
if (parent[x] == x) return x;
return parent[x] = root(parent[x]);
}
int unite(int x, int y) {
int rootX = root(x);
int rootY = root(y);
if (rootX == rootY) return rootY;
return parent[rootX] = rootY;
}
bool same(int x, int y) {
int rootX = root(x);
int rootY = root(y);
return rootX == rootY;
}
UnionFind dup() {
UnionFind d = UnionFind(parent.length.to!int);
d.parent = parent.dup;
d.option = option.dup;
return d;
}
}
Submission Info
| Submission Time |
|
| Task |
A - Server Room |
| User |
allegrogiken |
| Language |
D (LDC 1.20.1) |
| Score |
174391 |
| Code Size |
14183 Byte |
| Status |
AC |
| Exec Time |
2822 ms |
| Memory |
8260 KiB |
Judge Result
| Set Name |
test_all |
| Score / Max Score |
174391 / 1237500 |
| Status |
|
| Set Name |
Test Cases |
| test_all |
subtask_01_01.txt, subtask_01_02.txt, subtask_01_03.txt, subtask_01_04.txt, subtask_01_05.txt, subtask_01_06.txt, subtask_01_07.txt, subtask_01_08.txt, subtask_01_09.txt, subtask_01_10.txt, subtask_01_11.txt, subtask_01_12.txt, subtask_01_13.txt, subtask_01_14.txt, subtask_01_15.txt, subtask_01_16.txt, subtask_01_17.txt, subtask_01_18.txt, subtask_01_19.txt, subtask_01_20.txt, subtask_01_21.txt, subtask_01_22.txt, subtask_01_23.txt, subtask_01_24.txt, subtask_01_25.txt, subtask_01_26.txt, subtask_01_27.txt, subtask_01_28.txt, subtask_01_29.txt, subtask_01_30.txt, subtask_01_31.txt, subtask_01_32.txt, subtask_01_33.txt, subtask_01_34.txt, subtask_01_35.txt, subtask_01_36.txt, subtask_01_37.txt, subtask_01_38.txt, subtask_01_39.txt, subtask_01_40.txt, subtask_01_41.txt, subtask_01_42.txt, subtask_01_43.txt, subtask_01_44.txt, subtask_01_45.txt, subtask_01_46.txt, subtask_01_47.txt, subtask_01_48.txt, subtask_01_49.txt, subtask_01_50.txt |
| Case Name |
Status |
Exec Time |
Memory |
| subtask_01_01.txt |
AC |
2701 ms |
8108 KiB |
| subtask_01_02.txt |
AC |
2815 ms |
8116 KiB |
| subtask_01_03.txt |
AC |
640 ms |
8136 KiB |
| subtask_01_04.txt |
AC |
2599 ms |
8132 KiB |
| subtask_01_05.txt |
AC |
2216 ms |
8000 KiB |
| subtask_01_06.txt |
AC |
2682 ms |
8104 KiB |
| subtask_01_07.txt |
AC |
813 ms |
8136 KiB |
| subtask_01_08.txt |
AC |
2596 ms |
8212 KiB |
| subtask_01_09.txt |
AC |
2357 ms |
8200 KiB |
| subtask_01_10.txt |
AC |
2428 ms |
8144 KiB |
| subtask_01_11.txt |
AC |
484 ms |
8200 KiB |
| subtask_01_12.txt |
AC |
431 ms |
8240 KiB |
| subtask_01_13.txt |
AC |
2402 ms |
8100 KiB |
| subtask_01_14.txt |
AC |
2592 ms |
8112 KiB |
| subtask_01_15.txt |
AC |
2222 ms |
8020 KiB |
| subtask_01_16.txt |
AC |
2642 ms |
8108 KiB |
| subtask_01_17.txt |
AC |
2799 ms |
8260 KiB |
| subtask_01_18.txt |
AC |
2434 ms |
8020 KiB |
| subtask_01_19.txt |
AC |
514 ms |
8104 KiB |
| subtask_01_20.txt |
AC |
1029 ms |
8228 KiB |
| subtask_01_21.txt |
AC |
510 ms |
8240 KiB |
| subtask_01_22.txt |
AC |
664 ms |
8012 KiB |
| subtask_01_23.txt |
AC |
2335 ms |
8124 KiB |
| subtask_01_24.txt |
AC |
2815 ms |
8104 KiB |
| subtask_01_25.txt |
AC |
2371 ms |
8092 KiB |
| subtask_01_26.txt |
AC |
2373 ms |
8260 KiB |
| subtask_01_27.txt |
AC |
2603 ms |
8104 KiB |
| subtask_01_28.txt |
AC |
2493 ms |
8176 KiB |
| subtask_01_29.txt |
AC |
2789 ms |
8220 KiB |
| subtask_01_30.txt |
AC |
2791 ms |
8236 KiB |
| subtask_01_31.txt |
AC |
2702 ms |
8056 KiB |
| subtask_01_32.txt |
AC |
2770 ms |
8140 KiB |
| subtask_01_33.txt |
AC |
1733 ms |
8108 KiB |
| subtask_01_34.txt |
AC |
2750 ms |
8160 KiB |
| subtask_01_35.txt |
AC |
2562 ms |
8004 KiB |
| subtask_01_36.txt |
AC |
2665 ms |
8144 KiB |
| subtask_01_37.txt |
AC |
2439 ms |
8180 KiB |
| subtask_01_38.txt |
AC |
2822 ms |
8028 KiB |
| subtask_01_39.txt |
AC |
2598 ms |
8200 KiB |
| subtask_01_40.txt |
AC |
2448 ms |
8216 KiB |
| subtask_01_41.txt |
AC |
1098 ms |
8136 KiB |
| subtask_01_42.txt |
AC |
973 ms |
8016 KiB |
| subtask_01_43.txt |
AC |
2010 ms |
8236 KiB |
| subtask_01_44.txt |
AC |
1462 ms |
8000 KiB |
| subtask_01_45.txt |
AC |
928 ms |
8084 KiB |
| subtask_01_46.txt |
AC |
1201 ms |
8056 KiB |
| subtask_01_47.txt |
AC |
2404 ms |
8140 KiB |
| subtask_01_48.txt |
AC |
2571 ms |
8236 KiB |
| subtask_01_49.txt |
AC |
2330 ms |
8124 KiB |
| subtask_01_50.txt |
AC |
2365 ms |
8116 KiB |