結果
| 問題 | No.1479 Matrix Eraser |
| コンテスト | |
| ユーザー |
drken1215
|
| 提出日時 | 2026-06-06 00:24:45 |
| 言語 | C++23 (gcc 15.2.0 + boost 1.89.0) |
| 結果 |
TLE
|
| 実行時間 | - |
| コード長 | 11,571 bytes |
| 記録 | |
| コンパイル時間 | 3,987 ms |
| コンパイル使用メモリ | 387,168 KB |
| 実行使用メモリ | 6,400 KB |
| 最終ジャッジ日時 | 2026-06-06 00:25:27 |
| 合計ジャッジ時間 | 12,452 ms |
|
ジャッジサーバーID (参考情報) |
judge2_0 / judge1_0 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 2 |
| other | AC * 7 TLE * 1 -- * 31 |
ソースコード
// code template is in https://github.com/drken1215/algorithm/blob/master/template_minimum.cpp
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
using namespace std;
//------------------------------//
// Utility
//------------------------------//
using ll = long long;
using i128 = __int128_t;
using u128 = __uint128_t;
using pint = pair<int, int>;
using pll = pair<long long, long long>;
using tll = array<long long, 3>;
using fll = array<long long, 4>;
using vint = vector<int>;
using vll = vector<long long>;
using dint = deque<int>;
using dll = deque<long long>;
using vvint = vector<vector<int>>;
using vvll = vector<vector<long long>>;
using vpll = vector<pair<long long, long long>>;
template<class T> using min_priority_queue = priority_queue<T, vector<T>, greater<T>>;
template<class S, class T> inline bool chmax(S &a, T b) { return (a < b ? a = b, 1 : 0); }
template<class S, class T> inline bool chmin(S &a, T b) { return (a > b ? a = b, 1 : 0); }
template<class S, class T> inline auto maxll(S a, T b) { return max(ll(a), ll(b)); }
template<class S, class T> inline auto minll(S a, T b) { return min(ll(a), ll(b)); }
template<class T> auto max(const T &a) { return *max_element(a.begin(), a.end()); }
template<class T> auto min(const T &a) { return *min_element(a.begin(), a.end()); }
template<class T> auto argmax(const T &a) { return max_element(a.begin(), a.end()) - a.begin(); }
template<class T> auto argmin(const T &a) { return min_element(a.begin(), a.end()) - a.begin(); }
template<class T> auto accum(const vector<T> &a) { return accumulate(a.begin(), a.end(), T()); }
template<class T> auto accum(const deque<T> &a) { return accumulate(a.begin(), a.end(), T()); }
#define REP(i, a) for (long long i = 0; i < (long long)(a); i++)
#define REP2(i, a, b) for (long long i = a; i < (long long)(b); i++)
#define RREP(i, a) for (long long i = (a)-1; i >= (long long)(0); --i)
#define RREP2(i, a, b) for (long long i = (b)-1; i >= (long long)(a); --i)
#define EB emplace_back
#define PF push_front
#define PB push_back
#define MP make_pair
#define FI first
#define SE second
#define ALL(x) x.begin(), x.end()
#define COUT(x) cout << #x << " = " << (x) << " (L" << __LINE__ << ")" << endl
// input
template<class T> istream& operator >> (istream &is, vector<T> &P)
{ for (int i = 0; i < (int)P.size(); ++i) cin >> P[i]; return is; }
template<class T> istream& operator >> (istream &is, deque<T> &P)
{ for (int i = 0; i < (int)P.size(); ++i) cin >> P[i]; return is; }
template<class T> istream& operator >> (istream &is, vector<vector<T>> &P)
{ for (int i = 0; i < (int)P.size(); ++i) cin >> P[i]; return is; }
// output
template<class S, class T> ostream& operator << (ostream &s, const pair<S, T> &P)
{ return s << '<' << P.first << ", " << P.second << '>'; }
template<class T> ostream& operator << (ostream &s, const array<T, 2> &P)
{ return s << '<' << P[0] << "," << P[1] << '>'; }
template<class T> ostream& operator << (ostream &s, const array<T, 3> &P)
{ return s << '<' << P[0] << "," << P[1] << "," << P[2] << '>'; }
template<class T> ostream& operator << (ostream &s, const array<T, 4> &P)
{ return s << '<' << P[0] << "," << P[1] << "," << P[2] << "," << P[3] << '>'; }
template<class T> ostream& operator << (ostream &s, const vector<T> &P)
{ for (int i = 0; i < P.size(); ++i) { if (i > 0) { s << " "; } s << P[i]; } return s; }
template<class T> ostream& operator << (ostream &s, const deque<T> &P)
{ for (int i = 0; i < P.size(); ++i) { if (i > 0) { s << " "; } s << P[i]; } return s; }
template<class T> ostream& operator << (ostream &s, const vector<vector<T>> &P)
{ for (int i = 0; i < P.size(); ++i) { s << endl << P[i]; } return s << endl; }
template<class T> ostream& operator << (ostream &s, const set<T> &P)
{ for (auto it : P) { s << "<" << it << "> "; } return s; }
template<class T> ostream& operator << (ostream &s, const multiset<T> &P)
{ for (auto it : P) { s << "<" << it << "> "; } return s; }
template<class T> ostream& operator << (ostream &s, const unordered_set<T> &P)
{ for (auto it : P) { s << "<" << it << "> "; } return s; }
template<class S, class T> ostream& operator << (ostream &s, const map<S, T> &P)
{ for (auto it : P) { s << "<" << it.first << "->" << it.second << "> "; } return s; }
template<class S, class T> ostream& operator << (ostream &s, const unordered_map<S, T> &P)
{ for (auto it : P) { s << "<" << it.first << "->" << it.second << "> "; } return s; }
void yes(bool a) { cout << (a ? "yes" : "no") << endl; }
void YES(bool a) { cout << (a ? "YES" : "NO") << endl; }
void Yes(bool a) { cout << (a ? "Yes" : "No") << endl; }
const vector<int> DX = {1, 0, -1, 0, 1, -1, 1, -1};
const vector<int> DY = {0, 1, 0, -1, 1, -1, -1, 1};
// Hopcroft-Karp
struct HopcroftKarp {
const int NOT_MATCHED = -1;
// input
int size_left, size_right;
vector<vector<int>> list; // left to right
vector<vector<int>> rlist; // right to left
// results
vector<int> lr, rl;
// intermediate results
vector<bool> seen, matched;
vector<int> level;
// constructor
HopcroftKarp(int L, int R) : size_left(L), size_right(R), list(L), rlist(R) {}
void add_edge(int from, int to) {
assert(from >= 0 && from < size_left);
assert(to >= 0 && to < size_right);
list[from].emplace_back(to);
rlist[to].emplace_back(from);
}
// getter, debugger
const vector<int> &operator [] (int i) const {
return list[i];
}
friend ostream& operator << (ostream& s, const HopcroftKarp& G) {
s << endl;
for (int i = 0; i < (int)G.list.size(); ++i) {
s << i << ": ";
for (int j = 0; j < (int)G.list[i].size(); ++j) {
s << G.list[i][j];
if (j + 1 != (int)G.list[i].size()) s << ", ";
}
s << endl;
}
return s;
}
// solver
void hobfs() {
queue<int> que;
for (int left = 0; left < size_left; ++left) {
level[left] = -1;
if (!matched[left]) {
que.push(left);
level[left] = 0;
}
}
level[size_left] = size_left;
while (!que.empty()) {
int left = que.front();
que.pop();
for (int right : list[left]) {
int next = rl[right];
if (next == NOT_MATCHED) next = size_left;
if (level[next] == -1) {
level[next] = level[left] + 1;
que.push(next);
}
}
}
}
bool hodfs(int left) {
if (left == size_left) return true;
if (seen[left]) return false;
seen[left] = true;
for (int right : list[left]) {
int next = rl[right];
if (next == NOT_MATCHED) next = size_left;
if (level[next] > level[left] && hodfs(next)) {
lr[left] = right;
rl[right] = left;
return true;
}
}
return false;
}
int solve() {
seen.assign(size_left, false);
matched.assign(size_left, false);
level.assign(size_left + 1, -1);
lr.assign(size_left, -1);
rl.assign(size_right, -1);
int res = 0;
while (true) {
hobfs();
seen.assign(size_left, false);
bool finished = true;
for (int left = 0; left < size_left; ++left) {
if (!matched[left] && hodfs(left)) {
matched[left] = true;
++res;
finished = false;
}
}
if (finished) break;
}
for (int r = 0; r < size_right; r++) {
if (rl[r] != NOT_MATCHED) lr[rl[r]] = r;
}
return res;
}
// various construction
// max matching
vector<pair<int,int>> get_matching() {
vector<pair<int,int>> res;
for (int v = 0; v < size_left; v++) {
if (lr[v] == NOT_MATCHED) continue;
res.emplace_back(v, lr[v]);
}
return res;
}
// enumerate reachable nodes (0: left, 1: right)
const int LEFT = 0, RIGHT = 1;
pair<vector<bool>, vector<bool>> get_reachable() {
vector<bool> can_left(size_left, false);
vector<bool> can_right(size_right, false);
queue<pair<int,int>> que;
for (int v = 0; v < size_left; v++) {
if (lr[v] == NOT_MATCHED) {
can_left[v] = true;
que.push({LEFT, v});
}
}
while (!que.empty()) {
auto [which, v] = que.front();
que.pop();
if (which == LEFT) {
for (auto r : list[v]) {
if (!can_right[r]) {
can_right[r] = true;
que.push({RIGHT, r});
}
}
} else {
int l = rl[v];
if (l != NOT_MATCHED && !can_left[l]) {
can_left[l] = true;
que.push({LEFT, l});
}
}
}
return {can_left, can_right};
}
// max independent set (0: left, 1: right)
vector<pair<int,int>> get_independent_set() {
vector<pair<int,int>> res;
auto [can_left, can_right] = get_reachable();
for (int v = 0; v < size_left; v++) {
if (can_left[v]) res.emplace_back(LEFT, v);
}
for (int v = 0; v < size_right; v++) {
if (!can_right[v]) res.emplace_back(RIGHT, v);
}
return res;
}
// min vertex-cover (0: left, 1: right)
vector<pair<int,int>> get_vertex_cover() {
vector<pair<int,int>> res;
auto [can_left, can_right] = get_reachable();
for (int v = 0; v < size_left; v++) {
if (!can_left[v]) res.emplace_back(LEFT, v);
}
for (int v = 0; v < size_right; v++) {
if (can_right[v]) res.emplace_back(RIGHT, v);
}
return res;
}
// min edge-cover (0: left, 1: right)
vector<pair<int,int>> get_edge_cover() {
vector<pair<int,int>> res = get_matching();
for (int v = 0; v < size_left; v++) {
if (list[v].empty()) return vector<pair<int,int>>(); // infeasible
if (lr[v] == NOT_MATCHED) res.emplace_back(v, list[v][0]);
}
for (int v = 0; v < size_right; v++) {
if (rlist[v].empty()) return vector<pair<int,int>>(); // infeasible
if (rl[v] == NOT_MATCHED) res.emplace_back(rlist[v][0], v);
}
return res;
}
};
//------------------------------//
// Solver
//------------------------------//
int main() {
ll H, W; cin >> H >> W;
vvll A(H, vll(W)); cin >> A;
set<ll> S;
REP(i, H) REP(j, W) S.insert(A[i][j]);
ll res = 0;
for (auto val : S) {
if (val == 0) continue;
vll yoko, tate;
REP(i, H) {
bool exist = false;
REP(j, W) if (A[i][j] == val) exist = true;
if (exist) yoko.EB(i);
}
REP(j, W) {
bool exist = false;
REP(i, H) if (A[i][j] == val) exist = true;
if (exist) tate.EB(j);
}
ll L = yoko.size(), R = tate.size();
HopcroftKarp hk(L, R);
REP(i, L) REP(j, R) if (A[yoko[i]][tate[j]] == val) hk.add_edge(i, j);
res += hk.solve();
}
cout << res << endl;
}
drken1215