ABC460-多源BFS+欧几里得
1828 字
9 分钟
ABC460-多源BFS+欧几里得
ABC460-多源BFS+欧几里得
AtCoder Beginner Contest 460 - AtCoder
Easy:A、B、C
Hard:D、E
D-多源BFS
题意:
有一个H×W的网格,每个格子初始为白色(.)或黑色(#)。进行10^100次操作,每次操作同时对所有格子应用以下规则:
- 白色格子:如果其8邻域内至少有一个黑色格子,则变为黑色
- 黑色格子:变为白色
求10^100次操作后每个格子的颜色。
题解:
第一步:先进行一次特殊操作
- 不直接对原图进行BFS
- 而是先将原图进行一次变换:只有那些初始为白色且8邻域中有黑色的格子才被标记为黑色
- 这一步等价于”去掉孤立的黑色,只保留边界”
第二步:对变换后的图进行多源BFS
- 以变换后的黑色格子为源点
- 计算每个格子到最近黑色格子的切比雪夫距离
- 距离为偶数 → 白色(.),距离为奇数 → 黑色(#)
原始操作定义:
- 白色→黑色:当且仅当8邻域有黑色
- 黑色→白色:无条件
10^100次操作后(偶数次),相当于:
- 首先”过滤”掉那些会立即变白的初始黑色(因为没有白色邻居的黑色会变成孤立的白色)
- 然后黑色像”波”一样向外扩散,每次扩散一层
- 偶数次操作后,波前扩散了偶数层,所以距离奇偶性决定最终颜色
想象黑色是”波源”:
- 第1步:原黑色变白,它们周围的白色变黑(波向外扩散1层)
- 第2步:新黑色变白,它们周围的白色变黑(波再扩散1层)
- …
- 第k步:波扩散了k层
10^100是偶数,所以:
- 初始黑色的”波”扩散了偶数层
- 距离波源奇数层的格子最终是黑色
- 距离波源偶数层的格子最终是白色
但初始的孤立黑色(没有白色邻居)在第1步就变白了,不会成为波源。所以第一步要预处理,只保留有白色邻居的黑色作为波源。
from collections import deque
def solve(): H, W = map(int, input().split()) grid = [list(input().strip()) for _ in range(H)]
# 8个方向 dx = [1, 0, -1, 0, 1, -1, -1, 1] dy = [0, 1, 0, -1, 1, 1, -1, -1]
def in_bounds(x, y): return 0 <= x < H and 0 <= y < W
# 第一步:预处理,只保留有白色邻居的黑色 new_grid = [['.'] * W for _ in range(H)] for i in range(H): for j in range(W): if grid[i][j] == '#': # 检查8邻域是否有白色 for d in range(8): nx, ny = i + dx[d], j + dy[d] if in_bounds(nx, ny) and grid[nx][ny] == '.': new_grid[nx][ny] = '#'
grid = new_grid
# 第二步:多源BFS计算距离 INF = 10**9 dist = [[INF] * W for _ in range(H)] q = deque()
for i in range(H): for j in range(W): if grid[i][j] == '#': dist[i][j] = 0 q.append((i, j))
while q: x, y = q.popleft() for d in range(8): nx, ny = x + dx[d], y + dy[d] if in_bounds(nx, ny) and dist[nx][ny] == INF: dist[nx][ny] = dist[x][y] + 1 q.append((nx, ny))
# 第三步:根据距离奇偶性输出 for i in range(H): row = [] for j in range(W): if dist[i][j] % 2 == 0: row.append('.') else: row.append('#') print(''.join(row))
solve()#include <stdio.h>#include <stdlib.h>#include <string.h>
#define MAXN 1000005
typedef struct { int x, y;} Point;
Point q[MAXN];int head, tail;
int H, W;char grid[MAXN];char new_grid[MAXN];int dist[MAXN];
int dx[] = {1, 0, -1, 0, 1, -1, -1, 1};int dy[] = {0, 1, 0, -1, 1, 1, -1, -1};
int idx(int i, int j) { return i * W + j;}
int in_bounds(int x, int y) { return x >= 0 && x < H && y >= 0 && y < W;}
void push(int x, int y) { q[tail].x = x; q[tail].y = y; tail++;}
Point pop() { return q[head++];}
int empty() { return head == tail;}
int main() { scanf("%d %d", &H, &W);
for (int i = 0; i < H; i++) { scanf("%s", grid + i * W); }
// 第一步:预处理 memset(new_grid, '.', sizeof(new_grid));
for (int i = 0; i < H; i++) { for (int j = 0; j < W; j++) { if (grid[idx(i, j)] == '#') { for (int d = 0; d < 8; d++) { int nx = i + dx[d]; int ny = j + dy[d]; if (in_bounds(nx, ny) && grid[idx(nx, ny)] == '.') { new_grid[idx(nx, ny)] = '#'; } } } } }
memcpy(grid, new_grid, sizeof(grid));
// 第二步:BFS memset(dist, -1, sizeof(dist)); head = tail = 0;
for (int i = 0; i < H; i++) { for (int j = 0; j < W; j++) { if (grid[idx(i, j)] == '#') { dist[idx(i, j)] = 0; push(i, j); } } }
while (!empty()) { Point p = pop(); int x = p.x, y = p.y;
for (int d = 0; d < 8; d++) { int nx = x + dx[d]; int ny = y + dy[d];
if (in_bounds(nx, ny) && dist[idx(nx, ny)] == -1) { dist[idx(nx, ny)] = dist[idx(x, y)] + 1; push(nx, ny); } } }
// 第三步:输出 for (int i = 0; i < H; i++) { for (int j = 0; j < W; j++) { int id = idx(i, j); if (dist[id] % 2 == 0) { printf("."); } else { printf("#"); } } printf("\n"); }
return 0;}E-欧几里得
题意:
定义 concat(x,y) 为将x和y的十进制表示拼接起来形成的整数。例如 concat(123,45) = 12345。
给定N和M,求有多少对正整数(x,y),满足:
- 1 ≤ x ≤ N
- 1 ≤ y ≤ N
concat(x,y) ≡ x + y (mod M)
有T个测试用例,需要对998244353取模。
题解:
数学推导:
-
数学公式推导
一、基本定义与展开
设 的十进制位数为 ,即
拼接公式:
二、条件方程
代入拼接公式:
三、方程化简
两边同时减去 :
移项:
提取公因子 :
四、模方程的标准形式
这等价于:
即 整除 。
五、最大公约数化简
设:
由最大公约数定义,存在整数 满足:
且 。
六、整除条件转化
两边约去 :
七、互质性质的应用
由于 ,由欧几里得引理:
八、必要条件
其中:
记 ,则:
九、x的解集
数量:
十、y的约束
是 位数且不超过 :
记:
数量:
十一、总答案
第 组的贡献:
总答案(模 ):
十二、公式总结
MOD = 998244353def gcd(a, b): while b: a, b = b, a % b return aT = int(input())# 预计算10的幂pow10 = [1]for i in range(1, 19): pow10.append(pow10[-1] * 10)for _ in range(T): N, M = map(int, input().split()) # N的位数 len_N = len(str(N)) ans = 0 for k in range(1, len_N + 1): # 计算gcd和g d = gcd(M, pow10[k] - 1) g = M // d # x的个数 cnt_x = N // g if cnt_x == 0: continue # y的范围:k位数,且≤N L = pow10[k - 1] # 最小k位数 R = min(N, pow10[k] - 1) # 最大k位数 if L > R: continue cnt_y = R - L + 1 ans = (ans + cnt_x % MOD * (cnt_y % MOD)) % MOD print(ans % MOD) ABC460-多源BFS+欧几里得
http://blog.7a7a68.xyz/posts/abc460-多源bfs欧几里得/ 相关文章 智能推荐
1
ABC465-①C-双端队列②D-最近公共祖先③E-数位DP
AtCoder ABC465
2
ABC464-①C-差分②D-DP③倒序处理+并查集
AtCoder ABC464
3
ABC463-①C-离线查询+贪心/单调栈②D-二分答案③E-Dijkstra+虚拟节点④F-逆元+组合数学
AtCoder ABC463-solve4-补EF
4
ABC462-①排序②差分③数学④带权区间选择 DP
AtCoder ABC462-solve3-补DEF
5
ABC461-①贪心②前缀和+双指针③树状数组
AtCoder ABC461-solve3-补DE
随机文章 随机推荐