A – 奇妙的棋盘
一定要思考,不能想当然。这句话是说给我听的。
把连通块连边,每一次 BFS 扩展就算做一次点击,然后\(O(n^2)\)确定路径长度,再按奇偶性判断就行了。
// A.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 75, MAX_P = 4910, INF = 0x3f3f3f3f;
int n, m, mem[MAX_P], head[MAX_P], current, tot, dep[MAX_P];
char opt[MAX_N][MAX_N];
bool mp[MAX_P][MAX_P], vis[MAX_P];
struct edge
{
int to, nxt;
} edges[MAX_P << 3];
void addpath(int src, int dst)
{
edges[current].to = dst, edges[current].nxt = head[src];
head[src] = current++;
}
int getId(int x, int y) { return (x - 1) * m + y; }
int find(int x) { return x == mem[x] ? x : mem[x] = find(mem[x]); }
int main()
{
memset(head, -1, sizeof(head));
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%s", opt[i] + 1);
for (int i = 1; i <= n * m; i++)
mem[i] = i;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
if (i > 1 && opt[i][j] == opt[i - 1][j])
mem[find(getId(i - 1, j))] = mem[find(getId(i, j))];
if (j > 1 && opt[i][j] == opt[i][j - 1])
mem[find(getId(i, j - 1))] = mem[find(getId(i, j))];
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
if (vis[find(getId(i, j))] == false)
vis[find(getId(i, j))] = true, tot++;
if (i > 1 && opt[i][j] != opt[i - 1][j] && !mp[find(getId(i, j))][find(getId(i - 1, j))])
addpath(find(getId(i, j)), find(getId(i - 1, j))), addpath(find(getId(i - 1, j)), find(getId(i, j)));
if (j > 1 && opt[i][j] != opt[i][j - 1] && !mp[find(getId(i, j))][find(getId(i, j - 1))])
addpath(find(getId(i, j)), find(getId(i, j - 1))), addpath(find(getId(i, j - 1)), find(getId(i, j)));
}
int gans = INF;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
if (find(getId(i, j)) != getId(i, j))
continue;
memset(dep, 0x3f, sizeof(dep));
int id = getId(i, j), ans = 0;
queue<int> q;
q.push(id), dep[id] = 0;
while (!q.empty())
{
int u = q.front();
q.pop();
for (int i = head[u]; i != -1; i = edges[i].nxt)
if (dep[edges[i].to] == INF)
q.push(edges[i].to), dep[edges[i].to] = dep[u] + 1, ans = max(ans, dep[edges[i].to]);
}
if (((ans & 1) && opt[i][j] == 'W') || ((ans & 1) == 0 && opt[i][j] == 'B'))
ans++;
gans = min(gans, ans);
}
printf("%d", gans);
return 0;
}
// A.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 75, MAX_P = 4910, INF = 0x3f3f3f3f;
int n, m, mem[MAX_P], head[MAX_P], current, tot, dep[MAX_P];
char opt[MAX_N][MAX_N];
bool mp[MAX_P][MAX_P], vis[MAX_P];
struct edge
{
int to, nxt;
} edges[MAX_P << 3];
void addpath(int src, int dst)
{
edges[current].to = dst, edges[current].nxt = head[src];
head[src] = current++;
}
int getId(int x, int y) { return (x - 1) * m + y; }
int find(int x) { return x == mem[x] ? x : mem[x] = find(mem[x]); }
int main()
{
memset(head, -1, sizeof(head));
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%s", opt[i] + 1);
for (int i = 1; i <= n * m; i++)
mem[i] = i;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
if (i > 1 && opt[i][j] == opt[i - 1][j])
mem[find(getId(i - 1, j))] = mem[find(getId(i, j))];
if (j > 1 && opt[i][j] == opt[i][j - 1])
mem[find(getId(i, j - 1))] = mem[find(getId(i, j))];
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
if (vis[find(getId(i, j))] == false)
vis[find(getId(i, j))] = true, tot++;
if (i > 1 && opt[i][j] != opt[i - 1][j] && !mp[find(getId(i, j))][find(getId(i - 1, j))])
addpath(find(getId(i, j)), find(getId(i - 1, j))), addpath(find(getId(i - 1, j)), find(getId(i, j)));
if (j > 1 && opt[i][j] != opt[i][j - 1] && !mp[find(getId(i, j))][find(getId(i, j - 1))])
addpath(find(getId(i, j)), find(getId(i, j - 1))), addpath(find(getId(i, j - 1)), find(getId(i, j)));
}
int gans = INF;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
if (find(getId(i, j)) != getId(i, j))
continue;
memset(dep, 0x3f, sizeof(dep));
int id = getId(i, j), ans = 0;
queue<int> q;
q.push(id), dep[id] = 0;
while (!q.empty())
{
int u = q.front();
q.pop();
for (int i = head[u]; i != -1; i = edges[i].nxt)
if (dep[edges[i].to] == INF)
q.push(edges[i].to), dep[edges[i].to] = dep[u] + 1, ans = max(ans, dep[edges[i].to]);
}
if (((ans & 1) && opt[i][j] == 'W') || ((ans & 1) == 0 && opt[i][j] == 'B'))
ans++;
gans = min(gans, ans);
}
printf("%d", gans);
return 0;
}
// A.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 75, MAX_P = 4910, INF = 0x3f3f3f3f; int n, m, mem[MAX_P], head[MAX_P], current, tot, dep[MAX_P]; char opt[MAX_N][MAX_N]; bool mp[MAX_P][MAX_P], vis[MAX_P]; struct edge { int to, nxt; } edges[MAX_P << 3]; void addpath(int src, int dst) { edges[current].to = dst, edges[current].nxt = head[src]; head[src] = current++; } int getId(int x, int y) { return (x - 1) * m + y; } int find(int x) { return x == mem[x] ? x : mem[x] = find(mem[x]); } int main() { memset(head, -1, sizeof(head)); scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%s", opt[i] + 1); for (int i = 1; i <= n * m; i++) mem[i] = i; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { if (i > 1 && opt[i][j] == opt[i - 1][j]) mem[find(getId(i - 1, j))] = mem[find(getId(i, j))]; if (j > 1 && opt[i][j] == opt[i][j - 1]) mem[find(getId(i, j - 1))] = mem[find(getId(i, j))]; } for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { if (vis[find(getId(i, j))] == false) vis[find(getId(i, j))] = true, tot++; if (i > 1 && opt[i][j] != opt[i - 1][j] && !mp[find(getId(i, j))][find(getId(i - 1, j))]) addpath(find(getId(i, j)), find(getId(i - 1, j))), addpath(find(getId(i - 1, j)), find(getId(i, j))); if (j > 1 && opt[i][j] != opt[i][j - 1] && !mp[find(getId(i, j))][find(getId(i, j - 1))]) addpath(find(getId(i, j)), find(getId(i, j - 1))), addpath(find(getId(i, j - 1)), find(getId(i, j))); } int gans = INF; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { if (find(getId(i, j)) != getId(i, j)) continue; memset(dep, 0x3f, sizeof(dep)); int id = getId(i, j), ans = 0; queue<int> q; q.push(id), dep[id] = 0; while (!q.empty()) { int u = q.front(); q.pop(); for (int i = head[u]; i != -1; i = edges[i].nxt) if (dep[edges[i].to] == INF) q.push(edges[i].to), dep[edges[i].to] = dep[u] + 1, ans = max(ans, dep[edges[i].to]); } if (((ans & 1) && opt[i][j] == 'W') || ((ans & 1) == 0 && opt[i][j] == 'B')) ans++; gans = min(gans, ans); } printf("%d", gans); return 0; }
B – 生命
曼哈顿距离转切比雪夫距离板子题。
转换好坐标之后,搞二维前缀和即可。
// B.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 2300, MAX_P = 500010, DOM = 1010;
int n, k, q, lb, ub, dist[MAX_N][MAX_N], pts[MAX_N * MAX_N][2];
inline int getId(int x, int y) { return (x - 1) * n + y; }
int main()
{
scanf("%d%d%d", &n, &k, &q);
for (int i = 1, x, y; i <= k; i++)
scanf("%d%d", &x, &y), dist[x + y][x - y + n]++;
for (int x = 1; x <= n; x++)
for (int y = 1; y <= n; y++)
pts[getId(x, y)][0] = x + y, pts[getId(x, y)][1] = x - y + n;
for (int i = 1; i <= 2 * n; i++)
for (int j = 1; j <= 2 * n; j++)
dist[i][j] += dist[i - 1][j] + dist[i][j - 1] - dist[i - 1][j - 1];
for (int s, i = 1; i <= q; i++)
{
scanf("%d", &s);
if (s > n + 1)
printf("%d\n", k);
else
{
int ans = 0;
for (int i = 0, x0, y0, x1, y1; i <= getId(n, n); i++)
{
x0 = max(pts[i][0] - s - 1, 0), y0 = max(pts[i][1] - s - 1, 0);
x1 = min(pts[i][0] + s, n << 1), y1 = min(pts[i][1] + s, n << 1);
ans = max(ans, dist[x1][y1] - dist[x0][y1] - dist[x1][y0] + dist[x0][y0]);
}
printf("%d\n", ans);
}
}
return 0;
}
// B.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 2300, MAX_P = 500010, DOM = 1010;
int n, k, q, lb, ub, dist[MAX_N][MAX_N], pts[MAX_N * MAX_N][2];
inline int getId(int x, int y) { return (x - 1) * n + y; }
int main()
{
scanf("%d%d%d", &n, &k, &q);
for (int i = 1, x, y; i <= k; i++)
scanf("%d%d", &x, &y), dist[x + y][x - y + n]++;
for (int x = 1; x <= n; x++)
for (int y = 1; y <= n; y++)
pts[getId(x, y)][0] = x + y, pts[getId(x, y)][1] = x - y + n;
for (int i = 1; i <= 2 * n; i++)
for (int j = 1; j <= 2 * n; j++)
dist[i][j] += dist[i - 1][j] + dist[i][j - 1] - dist[i - 1][j - 1];
for (int s, i = 1; i <= q; i++)
{
scanf("%d", &s);
if (s > n + 1)
printf("%d\n", k);
else
{
int ans = 0;
for (int i = 0, x0, y0, x1, y1; i <= getId(n, n); i++)
{
x0 = max(pts[i][0] - s - 1, 0), y0 = max(pts[i][1] - s - 1, 0);
x1 = min(pts[i][0] + s, n << 1), y1 = min(pts[i][1] + s, n << 1);
ans = max(ans, dist[x1][y1] - dist[x0][y1] - dist[x1][y0] + dist[x0][y0]);
}
printf("%d\n", ans);
}
}
return 0;
}
// B.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 2300, MAX_P = 500010, DOM = 1010; int n, k, q, lb, ub, dist[MAX_N][MAX_N], pts[MAX_N * MAX_N][2]; inline int getId(int x, int y) { return (x - 1) * n + y; } int main() { scanf("%d%d%d", &n, &k, &q); for (int i = 1, x, y; i <= k; i++) scanf("%d%d", &x, &y), dist[x + y][x - y + n]++; for (int x = 1; x <= n; x++) for (int y = 1; y <= n; y++) pts[getId(x, y)][0] = x + y, pts[getId(x, y)][1] = x - y + n; for (int i = 1; i <= 2 * n; i++) for (int j = 1; j <= 2 * n; j++) dist[i][j] += dist[i - 1][j] + dist[i][j - 1] - dist[i - 1][j - 1]; for (int s, i = 1; i <= q; i++) { scanf("%d", &s); if (s > n + 1) printf("%d\n", k); else { int ans = 0; for (int i = 0, x0, y0, x1, y1; i <= getId(n, n); i++) { x0 = max(pts[i][0] - s - 1, 0), y0 = max(pts[i][1] - s - 1, 0); x1 = min(pts[i][0] + s, n << 1), y1 = min(pts[i][1] + s, n << 1); ans = max(ans, dist[x1][y1] - dist[x0][y1] - dist[x1][y0] + dist[x0][y0]); } printf("%d\n", ans); } } return 0; }
C – 死亡之树
这道题还是很好的。
考虑设计状态\(dp[vertexSet][leaveSet]\),总结点集合和叶子结点集合。每次转移的时候,都找一个新节点接到旧节点上。为了防止重复,我们保证新节点编号比旧节点大就行了。很好的一道题。
// C.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 11;
int mp[MAX_N][MAX_N], dp[1 << MAX_N][1 << MAX_N], n, m, k;
int main()
{
scanf("%d%d%d", &n, &m, &k);
for (int i = 1, x, y; i <= m; i++)
scanf("%d%d", &x, &y), mp[x - 1][y - 1] = mp[y - 1][x - 1] = 1;
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++)
if (mp[i][j])
dp[(1 << i) | (1 << j)][(1 << i) | (1 << j)] = 1;
for (int i = 1; i < (1 << n); i++)
for (int j = 1; j < (1 << n); j++)
if ((i & j) == j && dp[i][j] > 0 && __builtin_popcount(j) <= k)
for (int p = 0; p < n; p++)
if ((i & (1 << p)) == 0)
for (int to = 0; to < n; to++)
if (mp[p][to] && (i & (1 << to)) && (j & (~(1 << to))) < (1 << p))
dp[i ^ (1 << p)][j & (~(1 << to)) ^ (1 << p)] += dp[i][j];
int ans = 0;
for (int stat = 1; stat < (1 << n); stat++)
if (__builtin_popcount(stat) == k)
ans += dp[(1 << n) - 1][stat];
printf("%d", ans);
return 0;
}
// C.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 11;
int mp[MAX_N][MAX_N], dp[1 << MAX_N][1 << MAX_N], n, m, k;
int main()
{
scanf("%d%d%d", &n, &m, &k);
for (int i = 1, x, y; i <= m; i++)
scanf("%d%d", &x, &y), mp[x - 1][y - 1] = mp[y - 1][x - 1] = 1;
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++)
if (mp[i][j])
dp[(1 << i) | (1 << j)][(1 << i) | (1 << j)] = 1;
for (int i = 1; i < (1 << n); i++)
for (int j = 1; j < (1 << n); j++)
if ((i & j) == j && dp[i][j] > 0 && __builtin_popcount(j) <= k)
for (int p = 0; p < n; p++)
if ((i & (1 << p)) == 0)
for (int to = 0; to < n; to++)
if (mp[p][to] && (i & (1 << to)) && (j & (~(1 << to))) < (1 << p))
dp[i ^ (1 << p)][j & (~(1 << to)) ^ (1 << p)] += dp[i][j];
int ans = 0;
for (int stat = 1; stat < (1 << n); stat++)
if (__builtin_popcount(stat) == k)
ans += dp[(1 << n) - 1][stat];
printf("%d", ans);
return 0;
}
// C.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 11; int mp[MAX_N][MAX_N], dp[1 << MAX_N][1 << MAX_N], n, m, k; int main() { scanf("%d%d%d", &n, &m, &k); for (int i = 1, x, y; i <= m; i++) scanf("%d%d", &x, &y), mp[x - 1][y - 1] = mp[y - 1][x - 1] = 1; for (int i = 0; i < n; i++) for (int j = i + 1; j < n; j++) if (mp[i][j]) dp[(1 << i) | (1 << j)][(1 << i) | (1 << j)] = 1; for (int i = 1; i < (1 << n); i++) for (int j = 1; j < (1 << n); j++) if ((i & j) == j && dp[i][j] > 0 && __builtin_popcount(j) <= k) for (int p = 0; p < n; p++) if ((i & (1 << p)) == 0) for (int to = 0; to < n; to++) if (mp[p][to] && (i & (1 << to)) && (j & (~(1 << to))) < (1 << p)) dp[i ^ (1 << p)][j & (~(1 << to)) ^ (1 << p)] += dp[i][j]; int ans = 0; for (int stat = 1; stat < (1 << n); stat++) if (__builtin_popcount(stat) == k) ans += dp[(1 << n) - 1][stat]; printf("%d", ans); return 0; }