【题解】 [Codeforces-2B] The least round way

题目描述

题目大意

给定一个 \(n \times n\) 的矩阵,求一条从 \((1, 1)\)\((n, n)\) 的路径,使得路径上数的乘积末尾的0最少。
其中,\(2 \le n \le 1000\)

思路

该题主要考察:DP

首先,分析阶段性:显而易见,以走到的位置为阶段。
然后,定义状态:\(dp_{i, j}\) 表示从 \((1, 1)\)\((i, j)\) 的所有可能路径中,路径上数的乘积末尾的0最少的个数。
但是,状态难以转移。尝试将0分解为2和5。
于是,\(dp_{i, j, k}\) 表示从 \((1, 1)\)\((i, j)\) 的所有可能路径中,路径上数的乘积质因子k最少的个数。
其中,\(k = {2, 5}\)
那么从 \((1, 1)\)\((i, j)\) 的所有可能路径中,路径上数的乘积末尾的0最少的个数为 \(min(dp_{i, j, 2}, dp_{i, j, 5})\)
紧接着,分析状态转移方程:\((i, j)\) 由 上方 \((i - 1, j)\) 和 左方 \((i, j - 1)\) 转移而来。

\[dp_{i, j, 2} = min(dp_{i - 1, j, 2}, dp_{i, j - 1, 2}) + cnt2_{i, j} \]

\[dp_{i, j, 5} = min(dp_{i - 1, j, 5}, dp_{i, j - 1, 5}) + cnt5_{i, j} \]

其中, \(cnt2_{i, j}\)\(cnt5_{i, j}\) 分别表示 \((i, j)\) 上的数质因子2和5的个数。
最后,考虑初始化:\(dp_{1, 1, 2} = cnt2_{i, j}, dp_{1, 1, 5} = cnt5_{i, j}\)

但此题并不仅此,还有一种特殊情况:矩阵中有0。
只需要特判即可,如果DP的结果大于1且矩阵中有0,则结果为0。

代码

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

typedef long long LL;
typedef unsigned int UINT;
typedef unsigned long long ULL;

typedef pair<int, int> PII;
#define x first
#define y second

const int N = 1005;
int n, a[N][N];
int dp2[N][N], p2[N][N]; // p2 记录 质因子2最少的路径
int dp5[N][N], p5[N][N]; // p5 记录 质因子2最少的路径

int Get2(int x) // 计算一个数质因子2的个数
{
    if (!x) return 0;

    int ret = 0;
    for ( ; x % 2 == 0; x /= 2)
        ret ++ ;
    return ret;
}

int Get5(int x) // 计算一个数质因子5的个数
{
    if (!x) return 0;

    int ret = 0;
    for ( ; x % 5 == 0; x /= 5)
        ret ++ ;
    return ret;
}

void Print2(int i, int j) // 输出质因子2最少的路径
{
    if (i == 1 && j == 1) return ;

    if (p2[i][j] == 1)
    {
        Print2(i - 1, j);
        printf("D");
    }
    else
    {
        Print2(i, j - 1);
        printf("R");
    }
}

void Print5(int i, int j) // 输出质因子5最少的路径
{
    if (i == 1 && j == 1) return ;

    if (p5[i][j] == 1)
    {
        Print5(i - 1, j);
        printf("D");
    }
    else
    {
        Print5(i, j - 1);
        printf("R");
    }
}

signed main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= n; j ++ )
            scanf("%d", &a[i][j]);

    // 初始化
    memset(dp2, 0x3f, sizeof dp2), memset(dp5, 0x3f, sizeof dp5);
    dp2[1][1] = Get2(a[1][1]), dp5[1][1] = Get5(a[1][1]);

    bool flag = false; // flag 记录 是否有0的出现
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= n; j ++ )
        {
            if (a[i][j] == 0) flag = true; // 记录0的出现

            if (i > 1) // 由上方转移而来
            {
                if (dp2[i - 1][j] + Get2(a[i][j]) < dp2[i][j])
                {
                    dp2[i][j] = dp2[i - 1][j] + Get2(a[i][j]);
                    p2[i][j] = 1;
                }
                if (dp5[i - 1][j] + Get5(a[i][j]) < dp5[i][j])
                {
                    dp5[i][j] = dp5[i - 1][j] + Get5(a[i][j]);
                    p5[i][j] = 1;
                }
            }
            if (j > 1) // 由左方转移而来
            {
                if (dp2[i][j - 1] + Get2(a[i][j]) < dp2[i][j])
                {
                    dp2[i][j] = dp2[i][j - 1] + Get2(a[i][j]);
                    p2[i][j] = 2;
            }
            if (dp5[i][j - 1] + Get5(a[i][j]) < dp5[i][j])
            {
                    dp5[i][j] = dp5[i][j - 1] + Get5(a[i][j]);
                    p5[i][j] = 2;
            }
            }
        }

    int res = min(dp2[n][n], dp5[n][n]);
    if (flag && res > 1) // 特判特殊情况
    {
        puts("1");
        int x, y;
        for (int i = 1; i <= n; i ++ )
            for (int j = 1; j <= n; j ++ )
                if (a[i][j] == 0)
                {
                    x = i, y = j;
                    break;
                }
        for (int i = 1; i < x; i ++ ) printf("D");
        for (int i = 1; i < y; i ++ ) printf("R");
        for (int i = x; i < n; i ++ ) printf("D");
        for (int i = y; i < n; i ++ ) printf("R");
    }
    else
    {
        printf("%d\n", res);
        // 由最终结果取决路径。若质因子2的个数少于质因子5的个数,则输出质因子2最少的路径;反之亦然。
        if (dp2[n][n] < dp5[n][n]) Print2(n, n);
        else Print5(n, n);
    }

    return 0;
}
posted @ 2025-07-19 13:13  _TJHtjh  阅读(9)  评论(0)    收藏  举报