A,B 略。
C 建出一张图的邻接矩阵然后用 next_permutation
枚举排列判断是否能建立映射即可。
D 简单网格 dp,注意边界条件。
ABC232E - Rook Path
H × W H \times W H×W 的网格,你初始在 ( x 1 , y 1 ) (x_1, y_1) (x1,y1),要求做 K K K 次操作后位置变为 ( x 2 , y 2 ) (x_2, y_2) (x2,y2)。每次操作形如:
- 移动横坐标,从 ( x , y ) (x, y) (x,y) 移动到 ( x ′ , y ) (x', y) (x′,y),其中 1 ≤ x ′ ≤ H ∧ x ′ ≠ x 1\le x'\le H\land x'\neq x 1≤x′≤H∧x′=x。
- 移动纵坐标,从 ( x , y ) (x, y) (x,y) 移动到 ( x , y ′ ) (x, y') (x,y′),其中 1 ≤ y ′ ≤ W ∧ y ′ ≠ y 1\le y'\le W\land y'\neq y 1≤y′≤W∧y′=y。
(就是车的移动方式)问有多少种可能的操作方案,两种操作方案不同当且仅当中间某一步经过的点不同。答案对 998244353 998244353 998244353 取模。
根据套路,这个东西的横向移动和纵向移动是可以分开来考虑的。即,我们可以考虑横向上走 m m m 步的方案,再乘上纵向上走 K − m K - m K−m 步的方案,再乘上组合系数 ( K m ) \dbinom K m (mK)。考虑计算在一个方向上走 m m m 步的方案数。
可以 DP,设
f
0
/
1
,
i
f_{0/1, i}
f0/1,i 表示横向移动(纵向的类似)回到出发点与否,走
i
i
i 步的方案数,其中初始边界是
f
1
,
0
=
1
f_{1,0} = 1
f1,0=1,即走
0
0
0 步,终点在原点的方案数为
1
1
1。转移如下:
{
f
1
,
i
=
(
H
−
1
)
f
1
,
i
−
1
f
0
,
i
=
f
1
,
i
−
1
+
(
H
−
2
)
f
0
,
i
−
1
\begin{cases} f_{1, i} = (H - 1)f_{1, i - 1}\\ f_{0, i} = f_{1, i - 1} + (H - 2)f_{0, i - 1} \end{cases}
{f1,i=(H−1)f1,i−1f0,i=f1,i−1+(H−2)f0,i−1
转移的意义还是很显然的。于是我们
O
(
n
)
O(n)
O(n) 求出 dp 数组,这题就做完了,评测记录。
ABC232F - Simple Operations on Sequence
给定两个长度为 N N N( 2 ≤ N ≤ 18 2\le N\le 18 2≤N≤18): A i A_i Ai 和 B i B_i Bi( 1 ≤ A i , B i ≤ 1 0 8 1\le A_i, B_i\le 10^8 1≤Ai,Bi≤108)。可以进行如下两种操作,问最小的使得 A A A 变成 B B B 的操作代价:
- 对 A i A_i Ai 加一/减一,代价为 X X X( 1 ≤ X ≤ 1 0 8 1\le X\le 10^8 1≤X≤108)
- 交换 A A A 中的相邻元素,代价为 Y Y Y( 1 ≤ Y ≤ 1 0 16 1\le Y\le 10^{16} 1≤Y≤1016)
毫无疑问,两个操作是相互独立的,可以分开考虑。如果我们先交换,出一个
P
1
,
P
2
,
⋯
,
P
N
P_1, P_2,\cdots,P_N
P1,P2,⋯,PN 的排列,然后再统计第一个的答案。令
inv
(
P
)
\operatorname{inv}(P)
inv(P) 为
P
P
P 的逆序对数,则总代价为:
∑
i
=
1
N
∣
A
P
i
−
B
i
∣
⋅
X
+
inv
(
P
)
⋅
Y
\sum_{i = 1}^N|A_{P_i} - B_i|\cdot X + \operatorname{inv}(P)\cdot Y
i=1∑N∣APi−Bi∣⋅X+inv(P)⋅Y
把逆序对的这个关于
i
i
i 的贡献拆开,则我们可以得到
∑
i
=
1
N
(
∣
A
P
i
−
B
i
∣
⋅
X
+
∣
{
p
:
p
∈
{
1
,
2
,
⋯
,
N
}
\
{
P
1
,
⋯
,
P
i
−
1
}
,
p
<
P
i
}
∣
⋅
Y
)
\sum_{i = 1}^N(|A_{P_i} - B_i|\cdot X + |\{p:p\in\{1,2,\cdots, N\} \backslash \{P_1, \cdots, P_{i - 1}\}, p < P_i\}|\cdot Y)
i=1∑N(∣APi−Bi∣⋅X+∣{p:p∈{1,2,⋯,N}\{P1,⋯,Pi−1},p<Pi}∣⋅Y)
然后会发现一个很关键的地方:后面那个东西只和
{
P
1
,
⋯
,
P
i
}
\{P_1, \cdots, P_i\}
{P1,⋯,Pi} 这个集合有关,而这个集合很小,所以不妨考虑将其状压起来,令
f
(
x
,
S
)
f(x, S)
f(x,S) 表示
∣
p
:
p
∈
{
1
,
⋯
,
N
}
\
S
,
p
<
x
∣
|p:p\in\{1, \cdots, N\}\backslash S, p < x|
∣p:p∈{1,⋯,N}\S,p<x∣。然后式子改写为:
∑
i
=
1
N
(
∣
A
P
i
−
B
i
∣
⋅
X
+
f
(
P
i
,
{
P
1
,
⋯
,
P
i
−
1
}
)
⋅
Y
)
\sum_{i = 1}^N(|A_{P_i} - B_i|\cdot X + f(P_i, \{P_1, \cdots, P_{i - 1}\})\cdot Y)
i=1∑N(∣APi−Bi∣⋅X+f(Pi,{P1,⋯,Pi−1})⋅Y)
于是发现,这个东西可以状压 dp,具体地,设
d
p
S
dp_S
dpS 表示排列的前
∣
S
∣
|S|
∣S∣ 项是
S
S
S 内的元素,则转移应该是很好转移的。这题就做完了,评测记录。
ABC232G - Modulo Shortest Path
给定一张 N N N 个点的有向完全图,其中, i i i 到 j j j 的有向边边权为 ( A i + B j ) m o d M (A_i + B_j)\bmod M (Ai+Bj)modM。问 1 1 1 到 N N N 的最短路。
2 ≤ N ≤ 2 × 1 0 5 2\le N\le 2\times 10^5 2≤N≤2×105, 2 ≤ M ≤ 1 0 9 2\le M\le 10^9 2≤M≤109。
首先如果我们直接连边跑 Dij,那么必然会寄,边数是 O ( n 2 ) O(n^2) O(n2) 级别的,要想办法少下来。
考虑一个技巧,建一张新图:
- 构建 [ 0 , M ) [0, M) [0,M) 的虚点 0 ‾ , 1 ‾ , ⋯ , M − 1 ‾ \overline{0},\overline 1,\cdots,\overline{M - 1} 0,1,⋯,M−1。
- 然后 ∀ k ∈ [ 0 , M − 1 ) \forall k\in[0, M - 1) ∀k∈[0,M−1),连边 k ‾ → k + 1 ‾ \overline k\to \overline{k + 1} k→k+1,边权为 1 1 1。
- ∀ i ∈ [ 1 , N ] \forall i\in [1, N] ∀i∈[1,N],连边 i → − A i m o d M ‾ i\to \overline{-A_i\bmod M} i→−AimodM,边权为 0 0 0。
- ∀ i ∈ [ 1 , N ] \forall i\in [1, N] ∀i∈[1,N],连边 B i ‾ \overline{B_i} Bi,边权为 0 0 0。
这样一来,从 i i i 走到 j j j 就相当于,从 i i i 走到 − A i m o d M ‾ \overline{-A_i\bmod M} −AimodM,然后一步步走到 B j ‾ \overline{B_j} Bj,再走到 j j j。发现中间的路程刚好就是 ( A i + B j ) m o d M (A_i + B_j)\bmod M (Ai+Bj)modM,于是问题就得到了转化,我们求新图上 1 1 1 到 N N N 的最短路即可。
可是, O ( n + m ) O(n + m) O(n+m) 似乎也必死无疑。
然而我们可以发现,环上的很多点是没有用的,我们可以将其缩起来,会和原来的点连接的虚点只有 2 n 2n 2n 个,这样子点数和边数就都控制在了 O ( n ) O(n) O(n) 级别,直接跑 Dij 便可通过,时间复杂度 O ( n log n ) O(n\log n) O(nlogn),评测记录。
ABC232H - King’s Tour
不知道组题人怎么想的。。。这个题居然放在 H。
给定 H × W H\times W H×W 棋盘,一个国王初始在 ( 1 , 1 ) (1, 1) (1,1)。国王每步可以走到与其八连通的格子,请构造一个方案使得国王不重复地走完了每个格子,且终点为 ( a , b ) (a, b) (a,b)。 2 ≤ H , W ≤ 100 2\le H, W\le 100 2≤H,W≤100, ( a , b ) ≠ ( 1 , 1 ) (a, b)\neq (1, 1) (a,b)=(1,1)。
我们考虑减治构造。考虑如下几种情况:
H = 2 H = 2 H=2 或 W = 2 W = 2 W=2
如果 H = 2 H = 2 H=2,那么就可以像下面这样构造方案(图源 AtCoder 官方题解):
即,轨迹为: ( 1 , 1 ) → ( 2 , 1 ) → ⋯ → ( 1 , b ) → ( 1 , b + 1 ) → ⋯ → ( 1 , W ) → ( 2 , W ) → ⋯ → ( 2 , b ) (1, 1)\to (2, 1)\to\cdots\to(1, b)\to (1, b + 1)\to \cdots \to(1, W)\to (2, W)\to \cdots\to (2, b) (1,1)→(2,1)→⋯→(1,b)→(1,b+1)→⋯→(1,W)→(2,W)→⋯→(2,b)。如果 W = 2 W= 2 W=2,那么将行列调换之后是一样的。
H > 2 H > 2 H>2 且 W > 2 W > 2 W>2
考虑下面这个方案:
绿色圈出来的点集为 S S S,分类讨论:
- ( a , b ) ∉ S (a, b)\notin S (a,b)∈/S,则我们可以走完 S S S 内的点,然后垂直翻转一下坐标系,就变成了一个一模一样的子问题,递归处理即可。
- ( a , b ) ∈ S (a, b)\in S (a,b)∈S,则我们交换行列之后,就变成了 ( a , b ) ∉ S (a,b)\notin S (a,b)∈/S 的情况。
然后就可以递归地去解决这道题了。这种代码写的很巧妙:
using pii = pair<int, int>;
vector<pii> solve(int h, int w, int a, int b) {
vector<pii> ret;
if (h == 2) {
FOR(i, 1, b - 1) ret.push_back(pii(1, i)), ret.push_back(pii(2, i));
ret.push_back(pii(3 - a, b));
FOR(i, b + 1, w) ret.push_back(pii(1, i));
DEC(i, w, b + 1) ret.push_back(pii(2, i));
ret.push_back(pii(a, b));
} else if ((h > 2 && w == 2) || b == 1 || (a == h && b == 2)) {
ret = solve(w, h, b, a);
for (auto &p : ret) myswap(p.first, p.second);
} else {
FOR(i, 1, h) ret.push_back(pii(i, 1));
auto res = solve(h, w - 1, h + 1 - a, b - 1);
for (auto &p : res) p.first = h + 1 - p.first, ++p.second;
ret.insert(ret.end(), res.begin(), res.end());
}
return ret;
}
int main() {
int h, w, a, b; read(h, w, a, b);
auto ans = solve(h, w, a, b);
for (auto p : ans) print(p.first, p.second);
return output(), 0;
}