AtCoder Beginner Contest 232 题解(A-H)

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 1xHx=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 1yWy=y

(就是车的移动方式)问有多少种可能的操作方案,两种操作方案不同当且仅当中间某一步经过的点不同。答案对 998244353 998244353 998244353 取模。

根据套路,这个东西的横向移动和纵向移动是可以分开来考虑的。即,我们可以考虑横向上走 m m m 步的方案,再乘上纵向上走 K − m K - m Km 步的方案,再乘上组合系数 ( 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=(H1)f1,i1f0,i=f1,i1+(H2)f0,i1
转移的意义还是很显然的。于是我们 O ( n ) O(n) O(n) 求出 dp 数组,这题就做完了,评测记录。

ABC232F - Simple Operations on Sequence

给定两个长度为 N N N 2 ≤ N ≤ 18 2\le N\le 18 2N18): 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 1Ai,Bi108)。可以进行如下两种操作,问最小的使得 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 1X108
  • 交换 A A A 中的相邻元素,代价为 Y Y Y 1 ≤ Y ≤ 1 0 16 1\le Y\le 10^{16} 1Y1016

毫无疑问,两个操作是相互独立的,可以分开考虑。如果我们先交换,出一个 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=1NAPiBiX+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=1N(APiBiX+{p:p{1,2,,N}\{P1,,Pi1},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=1N(APiBiX+f(Pi,{P1,,Pi1})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 2N2×105 2 ≤ M ≤ 1 0 9 2\le M\le 10^9 2M109

首先如果我们直接连边跑 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,,M1
  • 然后 ∀ k ∈ [ 0 , M − 1 ) \forall k\in[0, M - 1) k[0,M1),连边 k ‾ → k + 1 ‾ \overline k\to \overline{k + 1} kk+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} iAimodM,边权为 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 2H,W100 ( 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 官方题解):

AtCoder Beginner Contest 232 题解(A-H)_第1张图片

即,轨迹为: ( 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

考虑下面这个方案:

AtCoder Beginner Contest 232 题解(A-H)_第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;
}

你可能感兴趣的:(题解,动态规划,算法,图论)