2025.8.18校队题单分享+总结
T1
P10804 [CEOI 2024] 玩具谜题
题目描述
CEOI 2024 的命题人 Ben 从科学委员会收到了一份礼物——一个玩具。这个玩具是个谜题,可以想象成一个 \(H\) 行 \(W\) 列的网格,上面放着一个金属物体。这个金属物体由两部分组成:一个横向的 \(1\) 行 \(K\) 列的部分和一个纵向的 \(L\) 行 \(1\) 列的部分,这两部分松散地连接在一起。它们都不能旋转,但可以在网格内水平或垂直滑动,只要它们始终重叠在一个方格上。
网格里还有一些障碍物。金属物体的任何部分都不能穿过障碍物,更糟糕的是,它们也不能(即使部分)移出网格。Ben 的任务是将金属物体从指定起始位置移动到(可能不同的)目标位置,使得两部分重叠在指定的目标方格上。
然而,Ben 玩这个玩具已经有一段时间了,还没有解开谜题。事实上,他开始怀疑组织者在捉弄他,给了他一个无解的谜题。因此,他向你求助,想知道这个谜题是否有解。
输入格式
输入的第一行包含四个空格分隔的整数 \(W, H, K, L\),分别表示谜题的宽度、高度、横向部分的宽度和纵向部分的高度。第二行包含四个整数 \(x_h, y_h, x_v, y_v\),表示横向部分最左上角方格的坐标和纵向部分最左上角方格的坐标。
行从上到下编号为 \(0\) 到 \(H-1\),列从左到右编号为 \(0\) 到 \(W-1\)。\(x\) 坐标表示列号,\(y\) 坐标表示行号。
接下来的 \(H\) 行每行包含 \(W\) 个字符,表示网格。字符 . 表示空方格,字符 X 表示障碍物,字符 * 表示目标方格。
保证金属物体的初始位置合法,即两部分重叠在一个方格上,并且两部分不与障碍物重叠也不超出网格。
只有一个目标方格,即玩具中只有一个字符 *,它可能与金属物体的初始位置重叠。
输出格式
如果可以将金属物体移动到目标方格,则输出一行 YES,否则输出 NO。
输入输出样例 #1
输入 #1
4 3 2 2
0 1 0 0
.X.*
....
...X
输出 #1
YES
输入输出样例 #2
输入 #2
2 3 2 3
0 1 0 0
.X
.*
.X
输出 #2
NO
说明/提示
样例解释 1
初始状态如下:

我们可以先将纵向部分向下移动一格,然后尽可能地交替移动横向和纵向部分,直到无法继续。接着,我们可以将纵向部分向上并向右移动,到达目标方格,最后将横向部分向上移动,也到达目标方格。
样例解释 2
无法移动纵向部分而不碰到障碍物,因此永远无法到达目标方格。
对于所有输入数据,满足:
- \(2 \leq W, H \leq 1\,500\)
- \(2 \leq K \leq W, 2 \leq L \leq H\)
- \(0 \leq x_h \leq W - K, 0 \leq y_h \leq H - 1\)
- \(0 \leq x_v \leq W - 1, 0 \leq y_v \leq H - L\)
详细子任务附加限制及分值如下表所示。
| 子任务 | 附加限制 | 分值 |
|---|---|---|
| \(1\) | \(W, H \le 50\) | \(14\) |
| \(2\) | \(W, H \le 90\) | \(21\) |
| \(3\) | \(W, H \le 300, K, L \le 10\) | \(9\) |
| \(4\) | \(W, H \le 360\) | \(29\) |
| \(5\) | 无附加限制 | \(27\) |
先暴力,状态是横着的和竖着的的左上角坐标,如题面所示,但是这样的时间复杂度是 \(O(H^2M^2)\)
通过枚举焦点减少状态量,交点的移动其实就可以判断出横竖的移动,交点左右动就是竖着的左右动,交点上下移动就是横着的上下动,再加上前缀后缀预处理,时间复杂度就降成了 \(O(H \times M)\) ;
给一个代码:
#include <bits/stdc++.h>
#define x first
#define y second
using namespace std;
const int N = 1510;
int n, m, K, L;
int sx, sy, tx, ty;
int Dx[4] = {-1, 0, 1, 0};
int Dy[4] = {0, 1, 0, -1};
struct Node1
{
int l, r;
};
struct Node2
{
Node1 X, Y;
};
char edge[N][N];
Node2 f[N][N];
bool st[N][N];
bool bfs()
{
queue<pair<int, int>> q;
q.push({sx, sy});
st[sx][sy] = true;
while(q.size())
{
pair<int, int> tmp = q.front();
q.pop();
int x = tmp.x, y = tmp.y;
if(x == tx && y == ty) return true;
for(int i = 0 ; i < 4 ; i ++ )
{
int dx = x + Dx[i], dy = y + Dy[i];
if((dx >= 1 && dx <= n && dy >= 1 && dy <= m && edge[dx][dy] != 'X' && !st[dx][dy]) == false) continue;
if(dy == y && (min(f[dx][dy].X.r, f[x][y].X.r) - max(f[dx][dy].X.l, f[x][y].X.l) + 1 >= K))
{
q.push({dx, dy});
st[dx][dy] = true;
}else if(dx == x && (min(f[x][y].Y.r, f[dx][dy].Y.r) - max(f[dx][dy].Y.l, f[x][y].Y.l) + 1 >= L))
{
q.push({dx, dy});
st[dx][dy] = true;
}
}
}
return false;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> m >> n >> K >> L;
int tmp = 0;
cin >> tmp >> sx >> sy >> tmp;
sx ++ ;
sy ++ ;
for(int i = 0 ; i <= n + 1 ; i ++ )
for(int j = 0 ; j <= m + 1 ; j ++ )
{
if(i >= 1 && i <= n && j >= 1 && j <= m) cin >> edge[i][j];
else edge[i][j] = 'X';
if(edge[i][j] == '*') tx = i, ty = j;
}
for(int i = 1 ; i <= n ; i ++ )
{
for(int j = 1 ; j <= m ; j ++ )
if(edge[i][j] != 'X')
f[i][j].X.l = (edge[i][j - 1] == 'X' ? j : f[i][j - 1].X.l);
for(int j = m ; j >= 1 ; j -- )
if(edge[i][j] != 'X')
f[i][j].X.r = (edge[i][j + 1] == 'X' ? j : f[i][j + 1].X.r);
}
for(int j = 1 ; j <= m ; j ++ )
{
for(int i = 1 ; i <= n ; i ++ )
if(edge[i][j] != 'X')
f[i][j].Y.l = (edge[i - 1][j] == 'X' ? i : f[i - 1][j].Y.l);
for(int i = n ; i >= 1 ; i -- )
if(edge[i][j] != 'X')
f[i][j].Y.r = (edge[i + 1][j] == 'X' ? i : f[i + 1][j].Y.r);
}
if(bfs()) cout << "YES";
else cout << "NO";
return 0;
}
T2
P6803 [CEOI 2020] 星际迷航
题目背景
原时空限制:0.2s,32m
题目描述
星际联邦由 \(N\) 颗行星组成,分别编号为 \(1 \sim N\)。一些行星间由星际通道相连。通过这些星际通道,飞船可以在短时间内往返于各星球之间。整个星际联邦中恰好有 \(N-1\) 条星际通道,并且通过这些星际通道,任意两颗行星之间均能相互抵达。
除了我们所处的宇宙之外,还有 \(D\) 个平行宇宙,这些平行宇宙是我们的宇宙的完全复刻,它们的行星,星际通道都和我们的完全相同。我们将这些平行宇宙编号为 \(1 \sim D\)(我们的宇宙编号为 \(0\)),记第 \(i\) 个宇宙的第 \(x\) 颗行星为 \(P_{x}^i\)。通过星门,我们可以在这些平行宇宙间穿梭。\(\forall i \in [0,D)\),我们将选择一个 \(A_i\) 和一个 \(B_i\)(要求 \(1 \leq A_i,B_i \leq N\)),在 \(P_{A_i}^i\) 和 \(P_{B_i}^{i+1}\) 之间搭建一个单向(只能从 \(P_{A_i}^i\) 前往 \(P_{B_i}^{i+1}\))星门。
当所有的星门都准备就绪后,联邦星舰 Batthyány 号将会开始它的处女航,它目前正环绕着 \(P_1^0\) 行星。Ágnes 舰长准备和 Gábor 中尉玩这样一个游戏:两个人交替选择星舰接下来前往的目的地,要求该目的地可以通过星际通道或星门直接抵达。他们希望每次前往的星球都是之前未抵达过的。即,如果星舰抵达了 \(P_{x}^i\),他们将不再经过这个星球(但是可以抵达 \(x\) 在其他平行宇宙中的相应星球)。由 Ágnes 舰长作为先手开始游戏,Gábor 中尉作为后手,当一位玩家在他的回合中,不能选择一个合法的目的地时,他就输掉了游戏。
舰长和中尉都是绝对聪明的,他们知道所有星际通道和星门的排布方案,并且他们每次都按照最优方案行动。你需要求出,有多少种布置星门的方案,使得作为先手的 Ágnes 舰长必胜?两种布置星门的方案是不同的,当且仅当存在一个整数 \(i\),使得 \(A_i\) 或 \(B_i\) 不同。
输入格式
第一行两个整数 \(N,D\),分别代表星际联邦拥有的行星数和平行宇宙的数量。
接下来 \(N-1\) 行,每行两个整数 \(u,v\),表示 \(\forall i \in [0,D]\),\(P_u^i,P_v^i\) 之间有星际通道相连。
输出格式
输出能使舰长必胜的星门布置方案数对 \(10^9+7\) 取模的结果。
输入输出样例 #1
输入 #1
3 1
1 2
2 3
输出 #1
4
说明/提示
样例解释
共有 \(3 \times 3=9\) 种本质不同的布置星门的方案,下面列出四种舰长必胜的情况。

子任务
所有数据均满足:\(1 \leq N \leq 10^5\),\(1 \leq D \leq 10^{18}\),\(1 \leq u,v \leq N\)。
各子任务的约束条件如下:
| 子任务编号 | 分值 | 约束 |
|---|---|---|
| \(1\) | \(0\) | 样例 |
| \(2\) | \(7\) | \(N=2\) |
| \(3\) | \(8\) | \(N \leq 100\),\(D=1\) |
| \(4\) | \(15\) | \(N \leq 1000\),\(D=1\) |
| \(5\) | \(15\) | \(D=1\) |
| \(6\) | \(20\) | \(N \leq 1000\),\(D \leq 10^5\) |
| \(7\) | \(20\) | \(D \leq 10^5\) |
| \(8\) | \(15\) | 无特殊约束 |

浙公网安备 33010602011771号