結果
| 問題 | No.5025 Forest Fire |
| コンテスト | |
| ユーザー |
occhan
|
| 提出日時 | 2026-10-24 17:06:06 |
| 言語 | C++23(gcc16) (gcc 16.2.0 + boost 1.92.0 + ACL) |
| 結果 |
AC
不安定
|
| 実行時間 | 1,860 ms / 2,000 ms |
| + 216µs | |
| コード長 | 6,556 bytes |
| 記録 | |
| コンパイル時間 | 3,469 ms |
| コンパイル使用メモリ | 363,928 KB |
| 実行使用メモリ | 9,928 KB |
| スコア | 173,420,538 |
| 最終ジャッジ日時 | 2026-10-24 17:08:49 |
| 合計ジャッジ時間 | 153,871 ms |
|
ジャッジサーバーID (参考情報) |
judge5_0 / <nil> |
| 純コード判定しない問題か言語 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 50 |
ソースコード
#include <bits/stdc++.h>
using namespace std;
static constexpr int MAXN = 50;
static constexpr int MAXV = MAXN * MAXN;
static constexpr int SAMPLES = 85;
static constexpr int CUT_STEPS = 250;
static constexpr int RESTORE_STEPS = 150;
int N, K, V;
vector<string> d;
vector<int> trees;
static unsigned char dry[SAMPLES][MAXV];
static unsigned char cutCell[MAXV];
static int ord_[MAXV], low_[MAXV], sub_[MAXV], parent_[MAXV];
static int sepSize_[MAXV], compId_[MAXV], compSize_[MAXV];
static long long sepSq_[MAXV];
static long long totalValue[MAXV];
static int timer_, compCnt_;
static int deg_[MAXV];
static int nbr_[MAXV][4];
static int ufParent[MAXV], ufSize[MAXV];
static long long restoreValue[MAXV];
inline int getD(int v) {
return d[v / N][v % N] - '0';
}
void dfsLow(int v, int s, int cid) {
ord_[v] = low_[v] = timer_++;
sub_[v] = 1;
compId_[v] = cid;
for (int z = 0; z < deg_[v]; ++z) {
int to = nbr_[v][z];
if (cutCell[to] || !dry[s][to]) continue;
if (ord_[to] == -1) {
parent_[to] = v;
dfsLow(to, s, cid);
sub_[v] += sub_[to];
low_[v] = min(low_[v], low_[to]);
if (low_[to] >= ord_[v]) {
sepSize_[v] += sub_[to];
sepSq_[v] += 1LL * sub_[to] * sub_[to];
}
} else if (to != parent_[v]) {
low_[v] = min(low_[v], ord_[to]);
}
}
}
inline void addCutValuesForSample(int s) {
fill(ord_, ord_ + V, -1);
fill(parent_, parent_ + V, -1);
fill(sepSize_, sepSize_ + V, 0);
fill(sepSq_, sepSq_ + V, 0LL);
timer_ = 0;
compCnt_ = 0;
for (int start : trees) {
if (cutCell[start]) continue;
if (!dry[s][start]) continue;
if (ord_[start] != -1) continue;
int cid = compCnt_++;
dfsLow(start, s, cid);
compSize_[cid] = sub_[start];
}
for (int v : trees) {
if (cutCell[v]) continue;
if (ord_[v] == -1) continue;
int S = compSize_[compId_[v]];
int remain =
S - 1 - sepSize_[v];
long long after =
sepSq_[v] +
1LL * remain * remain;
totalValue[v] +=
1LL * S * S - after;
}
}
inline int ufFind(int x) {
while (ufParent[x] != x) {
ufParent[x] =
ufParent[ufParent[x]];
x = ufParent[x];
}
return x;
}
inline void ufUnite(int a, int b) {
a = ufFind(a);
b = ufFind(b);
if (a == b) return;
if (ufSize[a] < ufSize[b]) {
swap(a, b);
}
ufParent[b] = a;
ufSize[a] += ufSize[b];
}
inline void addRestoreValuesForSample(int s) {
for (int v : trees) {
if (!cutCell[v] && dry[s][v]) {
ufParent[v] = v;
ufSize[v] = 1;
} else {
ufParent[v] = -1;
ufSize[v] = 0;
}
}
for (int v : trees) {
if (ufParent[v] == -1) continue;
int r = v / N;
int c = v % N;
if (r + 1 < N) {
int to = v + N;
if (ufParent[to] != -1) {
ufUnite(v, to);
}
}
if (c + 1 < N) {
int to = v + 1;
if (ufParent[to] != -1) {
ufUnite(v, to);
}
}
}
for (int v : trees) {
if (!cutCell[v]) continue;
if (!dry[s][v]) continue;
int roots[4];
int rootCount = 0;
long long mergedSize = 1;
long long before = 0;
for (int z = 0; z < deg_[v]; ++z) {
int to = nbr_[v][z];
if (ufParent[to] == -1) continue;
int root = ufFind(to);
bool duplicate = false;
for (int k = 0; k < rootCount; ++k) {
if (roots[k] == root) {
duplicate = true;
break;
}
}
if (duplicate) continue;
roots[rootCount++] = root;
long long sz = ufSize[root];
mergedSize += sz;
before += sz * sz;
}
long long after =
mergedSize * mergedSize;
restoreValue[v] +=
after - before;
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> N >> K;
V = N * N;
d.resize(N);
for (int i = 0; i < N; ++i) {
cin >> d[i];
}
trees.reserve(V);
for (int r = 0; r < N; ++r) {
for (int c = 0; c < N; ++c) {
int v = r * N + c;
if (d[r][c] != '0') {
trees.push_back(v);
}
if (r > 0) {
nbr_[v][deg_[v]++] = v - N;
}
if (r + 1 < N) {
nbr_[v][deg_[v]++] = v + N;
}
if (c > 0) {
nbr_[v][deg_[v]++] = v - 1;
}
if (c + 1 < N) {
nbr_[v][deg_[v]++] = v + 1;
}
}
}
mt19937 rng(123456789);
for (int s = 0; s < SAMPLES; ++s) {
for (int v : trees) {
dry[s][v] =
((int)(rng() % 10) < getD(v));
}
}
vector<int> cutList;
cutList.reserve(CUT_STEPS);
for (int step = 0;
step < CUT_STEPS &&
step < (int)trees.size();
++step) {
fill(
totalValue,
totalValue + V,
0LL);
for (int s = 0;
s < SAMPLES;
++s) {
addCutValuesForSample(s);
}
int best = -1;
for (int v : trees) {
if (cutCell[v]) continue;
if (best == -1 ||
totalValue[v] > totalValue[best] ||
(
totalValue[v] ==
totalValue[best] &&
(
getD(v) > getD(best) ||
(
getD(v) ==
getD(best) &&
v < best)))) {
best = v;
}
}
if (best == -1) break;
cutCell[best] = 1;
cutList.push_back(best);
}
int restoreSteps =
min(
RESTORE_STEPS,
max(
0,
(int)cutList.size() - K));
for (int step = 0;
step < restoreSteps;
++step) {
fill(
restoreValue,
restoreValue + V,
0LL);
for (int s = 0;
s < SAMPLES;
++s) {
addRestoreValuesForSample(s);
}
int best = -1;
for (int v : cutList) {
if (!cutCell[v]) continue;
if (best == -1 ||
restoreValue[v] <
restoreValue[best] ||
(
restoreValue[v] ==
restoreValue[best] &&
(
getD(v) < getD(best) ||
(
getD(v) ==
getD(best) &&
v < best)))) {
best = v;
}
}
if (best == -1) break;
cutCell[best] = 0;
}
vector<int> answer;
answer.reserve(K);
for (int v : trees) {
if (cutCell[v]) {
answer.push_back(v);
}
}
cout << answer.size() << '\n';
for (int v : answer) {
cout << v / N
<< ' '
<< v % N
<< '\n';
}
return 0;
}
occhan