Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
A final coloring only cares about the last time each row/column is painted. If a line is never the last painter of any cell, it was useless for the minimum value.
After assigning every row/column its last-paint color, each cell becomes . You may think order still matters inside the same color, but it doesn't: same color overwrites to the same color, so who cares.
For color to appear in the grid, you need at least one row and at least one column with label . If there are such rows and such columns, all higher-colored lines are forced, but among these color- lines you only need a minimum vertex cover of : exactly lines.
So the value is Now count label assignments by .
For an allowed set of higher colors, the number with value is Then inclusion-exclude over the higher colors so every one appears.
The clean way to model the process is this:
Give every row and column a label: the color used the last time that line is painted. If a line is never painted, pretend its label is .
For any cell, the final color is the color of the later-painted endpoint. Since operation colors never decrease, this is just
Same-color order does not matter. If both endpoints have color , the cell is either way. Shocking, I know.
Why the labels are unique
For a beautiful coloring, color appears. In a max-table , color can appear only if some row has label and some column has label .
Once that is true, labels are recoverable from the grid:
So counting valid label assignments is the same as counting colorings. No hidden overcounting nonsense.
The value of one label assignment
Suppose exactly rows have label , and exactly columns have label .
Every row/column with label greater than is forced to be painted. For example, if row has label , take any column with label ; the cell at their intersection has color , so row must be painted. Same argument for columns.
So all higher-colored lines cost
operations.
What about the color- rows and columns? Their only job is to color the submatrix where both endpoints have label . To cover every cell of this complete bipartite grid, we need either its row or its column painted. The minimum vertex cover of has size
Therefore the minimum number of operations is
That is the main punchline.
So if the value is , define
Then we need
Counting when higher colors are just allowed
First ignore the condition that every color appears.
Let be the number of allowed higher colors. We force color to appear by choosing:
The remaining rows and columns can independently choose any of the higher colors.
For fixed , this gives
For value , we need . So define
Compute that with prefix sums:
When is bigger than or , the sum just stops at that dimension.
Forcing all colors
The formula counts colorings where color appears, and all other used colors are chosen from some allowed set of size .
A higher color appears in the grid iff it appears as at least one row/column label, because there is a label- line on the opposite side.
So we use inclusion-exclusion over the higher colors:
That removes labelings missing at least one required higher color.
Complexity
For each , compute the row and column prefix sums and add its inclusion-exclusion contribution to every answer. This is
plus factorial precomputation, easily fine for .
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
const int MOD = 998244353;
int addmod(int a, int b) {
a += b;
if (a >= MOD) a -= MOD;
if (a < 0) a += MOD;
return a;
}
int submod(int a, int b) {
a -= b;
if (a < 0) a += MOD;
return a;
}
int mulmod(int a, int b) {
return int(1LL * a * b % MOD);
}
int modpow(int a, int e) {
int r = 1;
while (e > 0) {
if (e & 1) r = mulmod(r, a);
a = mulmod(a, a);
e >>= 1;
}
return r;
}
int main() {
setIO();
int n, m, k;
cin >> n >> m >> k;
int lim = n + m + 5;
vector<int> fact(lim), ifact(lim);
fact[0] = 1;
for (int i = 1; i < lim; i++) fact[i] = mulmod(fact[i - 1], i);
ifact[lim - 1] = modpow(fact[lim - 1], MOD - 2);
for (int i = lim - 1; i >= 1; i--) ifact[i - 1] = mulmod(ifact[i], i);
auto C = [&](int a, int b) -> int {
if (b < 0 || b > a) return 0;
return mulmod(fact[a], mulmod(ifact[b], ifact[a - b]));
};
auto get = [](const vector<int>& pref, int idx) -> int {
if (idx < (int)pref.size()) return pref[idx];
return pref.back();
};
vector<int> ans(n + m, 0);
int mx = max(n, m);
for (int x = 0; x < k; x++) {
vector<int> powx(mx + 1, 1);
for (int e = 1; e <= mx; e++) powx[e] = mulmod(powx[e - 1], x);
vector<int> pr(n + 2, 0), pc(m + 2, 0);
for (int r = 1; r <= n; r++) {
pr[r + 1] = addmod(pr[r], mulmod(C(n, r), powx[n - r]));
}
for (int c = 1; c <= m; c++) {
pc[c + 1] = addmod(pc[c], mulmod(C(m, c), powx[m - c]));
}
int coef = C(k - 1, x);
if ((k - 1 - x) & 1) coef = submod(0, coef);
for (int t = 1; t <= mx; t++) {
int cur = mulmod(get(pr, t + 1), get(pc, t + 1));
int old = mulmod(get(pr, t), get(pc, t));
int ways = submod(cur, old);
int s = n + m - t;
ans[s] = addmod(ans[s], mulmod(coef, ways));
}
}
for (int s = min(n, m); s <= n + m - 1; s++) {
cout << ans[s] << ' ';
}
cout << '\n';
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
const int MOD = 998244353;
int addmod(int a, int b) {
a += b;
if (a >= MOD) a -= MOD;
if (a < 0) a += MOD;
return a;
}
int submod(int a, int b) {
a -= b;
if (a < 0) a += MOD;
return a;
}
int mulmod(int a, int b) {
return int(1LL * a * b % MOD);
}
int modpow(int a, int e) {
int r = 1;
while (e > 0) {
if (e & 1) r = mulmod(r, a);
a = mulmod(a, a);
e >>= 1;
}
return r;
}
int main() {
setIO();
int n, m, k;
cin >> n >> m >> k;
int lim = n + m + 5;
vector<int> fact(lim), ifact(lim);
fact[0] = 1;
for (int i = 1; i < lim; i++) fact[i] = mulmod(fact[i - 1], i);
ifact[lim - 1] = modpow(fact[lim - 1], MOD - 2);
for (int i = lim - 1; i >= 1; i--) ifact[i - 1] = mulmod(ifact[i], i);
auto C = [&](int a, int b) -> int {
if (b < 0 || b > a) return 0;
return mulmod(fact[a], mulmod(ifact[b], ifact[a - b]));
};
auto get = [](const vector<int>& pref, int idx) -> int {
if (idx < (int)pref.size()) return pref[idx];
return pref.back();
};
vector<int> ans(n + m, 0);
int mx = max(n, m);
for (int x = 0; x < k; x++) {
vector<int> powx(mx + 1, 1);
for (int e = 1; e <= mx; e++) powx[e] = mulmod(powx[e - 1], x);
vector<int> pr(n + 2, 0), pc(m + 2, 0);
for (int r = 1; r <= n; r++) {
pr[r + 1] = addmod(pr[r], mulmod(C(n, r), powx[n - r]));
}
for (int c = 1; c <= m; c++) {
pc[c + 1] = addmod(pc[c], mulmod(C(m, c), powx[m - c]));
}
int coef = C(k - 1, x);
if ((k - 1 - x) & 1) coef = submod(0, coef);
for (int t = 1; t <= mx; t++) {
int cur = mulmod(get(pr, t + 1), get(pc, t + 1));
int old = mulmod(get(pr, t), get(pc, t));
int ways = submod(cur, old);
int s = n + m - t;
ans[s] = addmod(ans[s], mulmod(coef, ways));
}
}
for (int s = min(n, m); s <= n + m - 1; s++) {
cout << ans[s] << ' ';
}
cout << '\n';
return 0;
}