Solving ARC143 Problems with Strategic Insights
Given three values A, B, and C where A < B < C, if A + B < C, no valid solution exists; otherwise, the answer is simply C.
For the second problem, consider an N×N grid filled with numbers from 1 to N². The task is to count configurations where no row minimum equals any column maximum. Define "bad" cells as those where a row minimum coincides with a column maximum. If there are two such bad cells, their intersections lead to contradictory ordering constraints, implying at most one bad cell can exist. Enumerate possible values for this single bad cell, fill its row and column accordingly, and permute the remaining entries freely. The total number of invalid configurations is computed using combinatorics and modular arithmetic.
#include <cstdio>
using namespace std;
int read(){
char c = getchar(); int x = 0;
while (c < 48 || c > 57) c = getchar();
do x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
while (c >= 48 && c <= 57);
return x;
}
const int P = 998244353;
const int N = 250003;
int fac[N], fiv[N], inv[N];
int C(int n, int k) {
if (k < 0 || k > n) return 0;
return 1LL * fac[n] * fiv[n - k] % P;
}
int main() {
int n = read();
fac[0] = fiv[0] = inv[1] = 1;
for (int i = 1; i <= n * n; ++i) {
if (i > 1) inv[i] = 1LL * inv[P % i] * (P - P / i) % P;
fac[i] = 1LL * fac[i - 1] * i % P;
fiv[i] = 1LL * fiv[i - 1] * inv[i] % P;
}
int res = fac[n * n];
for (int i = 1; i <= n * n; ++i)
res = (res + P - 1LL * n * n * C(i - 1, n - 1) % P * C(n * n - i, n - 1) % P * fac[n * n - 2 * n + 1] % P) % P;
printf("%d\n", res);
return 0;
}
The third problem involves a game on piles of stones. Player One removes X stones from selected piles, Player Two removes Y stones from selected piles, each move must affect at least one pile, and the player unable to move loses. First player starts. The key idea is to analyze stone counts modulo (X+Y). If all residues are in [0, X), then Second wins: any move by First creates residues in [X, X+Y), allowing Second to respond symmetrically untill First cannot act. Conversely, if any residue lies in [X, X+Y), check whether First can force all residue into [0, Y). If not, and X > Y, Second can always push First into losing state. Otherwise, First has a winning strategy.
#include <cstdio>
using namespace std;
int read(){
char c = getchar(); int x = 0;
while (c < 48 || c > 57) c = getchar();
do x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
while (c >= 48 && c <= 57);
return x;
}
int main(){
int n = read(), a = read(), b = read();
if (a > b) {
for (int i = 1; i <= n; ++i) {
int t = read();
if (t % (a + b) < b) continue;
if (t >= a && (t - a) % (a + b) < b) continue;
puts("Second");
return 0;
}
puts("First");
return 0;
} else {
for (int i = 1; i <= n; ++i) {
int t = read();
if (t % (a + b) < a) continue;
puts("First");
return 0;
}
puts("Second");
return 0;
}
return 0;
}
For the fourth problem, we have a graph with 2N nodes where node i connects to node i+N. Given m pairs (a_i, b_i), we must choose either edge (a_i+N, b_i) or (a_i, b_i+N). Goal: minimize the number of bridges. Observe that edges of type (i, i+N) are candidates for being bridges. To reduce bridge count, aim to form cycles via smart edge selection. Perform DFS on the graph and assign directions dynamically: if an edge leads to unvisited node, use it in forward direction; otherwise, reverse. This ensures maximal cycle formation. Output '1' if the chosen edge is (a_i+N, b_i), '0' otherwise.
#include <cstdio>
using namespace std;
int read(){
char c = getchar(); int x = 0;
while (c < 48 || c > 57) c = getchar();
do x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
while (c >= 48 && c <= 57);
return x;
}
const int N = 200003;
int a[N], b[N];
int n, m;
int hd[N], ver[N<<1], nxt[N<<1], id[N<<1], tot;
bool dir[N<<1], sd[N], ok[N];
void add(int u, int v, int w, bool d) { nxt[++tot] = hd[u]; hd[u] = tot; ver[tot] = v; id[tot] = w; dir[tot] = d; }
bool vis[N];
int rk[N], num;
void dfs(int u) {
vis[u] = 1; rk[u] = ++num;
for (int i = hd[u]; i; i = nxt[i]) {
if (!ok[id[i]]) sd[id[i]] = dir[i], ok[id[i]] = 1;
if (!vis[ver[i]]) dfs(ver[i]);
}
}
int main() {
n = read(); m = read();
for (int i = 1; i <= m; ++i) a[i] = read();
for (int i = 1; i <= m; ++i) b[i] = read();
for (int i = 1; i <= m; ++i) {
add(a[i], b[i], i, 0);
add(b[i], a[i], i, 1);
}
for (int i = 1; i <= n; ++i) if (!vis[i]) dfs(i);
for (int i = 1; i <= m; ++i) if (sd[i]) putchar('1'); else putchar('0');
putchar('\n');
return 0;
}
In the fifth problem, a tree has coins facing up (W) or down (B). Operation: remove a W coin, then flip all adjacent coins. Determine if all coins can be removed. For each coin, define d_u as the time it's removed. For a W coin, the number of neighbors removed earlier must be even; for B, odd. Use post-order traversal: leaf nodes determine relation with parent. Propagate constraints upward. If root fails parity check, no solution. Otherwise, build dependency graph based on relative removal times and perform topological sort using min-heap to ensure lexicographical smallest order.
#include <cstdio>
#include <queue>
using namespace std;
int read(){
char c = getchar(); int x = 0;
while (c < 48 || c > 57) c = getchar();
do x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
while (c >= 48 && c <= 57);
return x;
}
const int N = 200003;
priority_queue<int, vector<int>, greater<int>> q;
int n, rk, o[N];
int hd[N], ver[N<<1], nxt[N<<1], tot;
int deg[N], ft[N], ghd[N], gver[N], gnxt[N], gtot;
bool s[N];
void add(int u, int v) { nxt[++tot] = hd[u]; hd[u] = tot; ver[tot] = v; }
void gadd(int u, int v) { gnxt[++gtot] = ghd[u]; ghd[u] = gtot; gver[gtot] = v; }
bool dfs(int u, int fa) {
ft[u] = fa;
for (int i = hd[u], v; i; i = nxt[i])
if ((v = ver[i]) ^ fa)
s[u] ^= !dfs(v, u);
return s[u];
}
int main() {
n = read();
for (int i = 1; i < n; ++i) {
int u = read(), v = read();
add(u, v); add(v, u);
}
char c = getchar();
while (c != 'W' && c != 'B') c = getchar();
for (int i = 1; i <= n; ++i) s[i] = (c == 'B'), c = getchar();
if (dfs(1, 0)) { puts("-1"); return 0; }
for (int i = 2; i <= n; ++i)
if (s[i]) gadd(ft[i], i), ++deg[i];
else gadd(i, ft[i]), ++deg[ft[i]];
for (int i = 1; i <= n; ++i) if (!deg[i]) q.push(i);
while (!q.empty()) {
int u = q.top(); q.pop();
printf("%d ", u);
for (int i = ghd[u]; i; i = gnxt[i])
if (--deg[gver[i]] == 0) q.push(gver[i]);
}
putchar('\n');
return 0;
}