F - Path to Integer

F - Path to Integer

Problem Statement

There is an $N\times N$ grid. Let cell $(i,j)$ denote the cell in the $i$-th row from the top and $j$-th column from the left. Each cell contains a digit from 1 to 9; cell $(i,j)$ contains $A_{i,j}$.

Initially, a token is on cell $(1,1)$. Let $S$ be an empty string. Repeat the following operation $2N-1$ times:

  • Append to the end of $S$ the digit in the current cell.
  • Move the token one cell down or one cell to the right. However, do not move it in the $(2N-1)$-th operation.

After $2N-1$ operations, the token is on cell $(N,N)$ and the length of $S$ is $2N-1$.

Interpret $S$ as an integer. The score is the remainder when this integer is divided by $M$.

Find the maximum achievable score.

Constraints

  • $1 \leq N \leq 20$
  • $2 \leq M \leq 10^9$
  • $1 \leq A_{i,j} \leq 9$
  • All input values are integers.

Input

The input is given from Standard Input in the following format:

$N$ $M$
$A_{1,1}$ $A_{1,2}$ $\ldots$ $A_{1,N}$
$A_{2,1}$ $A_{2,2}$ $\ldots$ $A_{2,N}$
$\vdots$
$A_{N,1}$ $A_{N,2}$ $\ldots$ $A_{N,N}$

Output

Print the answer.


Sample Input 1

2 7
1 2
3 1

Sample Output 1

5

There are two ways to move the token:

  • Move through $(1,1),(1,2),(2,2)$. Then $S=$ 121, and the score is the remainder when $121$ is divided by $7$, which is $2$.
  • Move through $(1,1),(2,1),(2,2)$. Then $S=$ 131, and the score is the remainder when $131$ is divided by $7$, which is $5$.

The maximum score is $5$, so print $5$.


Sample Input 2

3 100000
1 2 3
3 5 8
7 1 2

Sample Output 2

13712

Sample Input 3

5 402
8 1 3 8 9
8 2 4 1 8
4 1 8 5 9
6 2 1 6 7
6 6 7 7 6

Sample Output 3

384

 

解题思路

  经典 Attention Is All You Need。

  性质 1:如果经过格子 $(i,j) \, (0 \leq i, j <n)$,那么 $a_{i,j}$ 必然在最终得到的十进制数的第 $2n-2-(i+j)$ 位(从低位往高位数)。因此每个格子上的位置可以进行替换 $a_{i,j} \gets a_{i,j} \times 10^{2n-2-(i+j)} \bmod m$,这样就可以从原本的每个格子拼成十进制数取模,等价变成每个格子求和取模。

  性质 2:从 $(0,0)$ 每次只能往右或往下移动到 $(n-1, n-1)$,必定恰好经过反对角线上的一个格子(即 $(0, n-1), (1, n-2), \ldots (i, n-1-i), \ldots, (n-1, 0)$ 中的一个)。否则可以通过反证法证明,如果经过至少两个反对角线上的格子,一定存在某步往左或往上走。

  知道这两个性质就好做了,可以根据第二个性质枚举经过的反对角线上的格子。如果经过反对角线格子 $(i,n-1-i)$,此时我们先暴力求出从 $(0,0)$ 走到 $(i, n-1-i)$(含)所有可能的分数(即路径上格子的和),并存到集合 $S$ 中。用同样的方法再求出从 $(i, n-1-i)$(不含)走到 $(n-1, n-1)$ 所有可能的分数并存到集合 $T$ 中。然后枚举 $S$ 中的每个元素 $x$,为了使得取模后分数最大,应该在 $T$ 中找到不超过 $m-1-x$ 的最大值 $y$。如果 $y$ 存在那么对于固定的 $x$ 取模后最大的分数就是 $x+y$;否则 $y$ 不存在,此时 $y$ 应该取 $T$ 中的最大值,取模后最大的分数是 $x+y-m$。

  可以通过 dfs 暴力求出从 $(0,0)$ 到 $(i,n-1-i)$ 所有可能的分数,有 $C_{n-1}^{i}$ 种走法(从 $(0,0)$ 走到 $(i,n-1-i)$ 需要 $n-1$ 步,相当于从 $n-1$ 步中选出 $i$ 步用于往右走)。因此对于每个反对角线上的格子,总的方案数是 $\sum\limits_{i=0}^{n-1}{C_{n-1}^{i}} = 2^{n-1}$,对应的 dfs 复杂度为 $O(2^n)$,不会超时。同理从 $(i, n-1-i)$ 走到 $(n-1, n-1)$,等价于从 $(n-1, n-1)$ 每次往左或往右走到反对角线,复杂度也是 $O(2^n)$。

  AC 代码如下,时间复杂度为 $O(n 2^n)$:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 25;

int n, m;
int g[N][N], p[N * 2];
set<int> st[N * N];
int ans;

void dfs1(int x, int y, int s) {
    if (x + y == n - 1) {
        st[x * n + y].insert(s);
        return;
    }
    if (x + 1 < n) dfs1(x + 1, y, (s + g[x + 1][y]) % m);
    if (y + 1 < n) dfs1(x, y + 1, (s + g[x][y + 1]) % m);
}

void dfs2(int x, int y, int s) {
    if (x + y == n - 1) {
        s = (s - g[x][y] + m) % m;
        int t = x * n + y;
        auto it = st[t].upper_bound(m - 1 - s);
        if (it == st[t].begin()) ans = max(ans, s + *st[t].rbegin() - m);
        else ans = max(ans, s + *prev(it));
        return;
    }
    if (x - 1 >= 0) dfs2(x - 1, y, (s + g[x - 1][y]) % m);
    if (y - 1 >= 0) dfs2(x, y - 1, (s + g[x][y - 1]) % m);
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    p[0] = 1;
    for (int i = 1; i < n << 1; i++) {
        p[i] = p[i - 1] * 10ll % m;
    }
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cin >> g[i][j];
            g[i][j] = 1ll * g[i][j] * p[2 * n - 2 - i - j] % m;
        }
    }
    dfs1(0, 0, g[0][0]);
    dfs2(n - 1, n - 1, g[n - 1][n - 1]);
    cout << ans;
    
    return 0;
}

 

参考资料

  Editorial - Tokio Marine & Nichido Fire Insurance Programming Contest 2025 (AtCoder Beginner Contest 402):https://atcoder.jp/contests/abc402/editorial/12763

posted @ 2025-05-03 16:46  onlyblues  阅读(29)  评论(0)    收藏  举报
Web Analytics