链接
传送门
题意
给出一个\(n*n\)的矩阵,起点在左上角,每次只能向右或向下,求到到右下角的路径使其所有数字的乘积末尾的零的个数最少。输出零的个数和路径。
思路
末尾零的个数即为路径之积分解后2的指数和5的指数的最小值,首先预处理出所有数字分解后2和5的指数,然后类似于数字三角形的DP。唯一的trick是数字中出现0。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
| #include <bits/stdc++.h> using namespace std;
typedef long long LL; const int inf = 50000; const int maxn = 1010; const int fac[] = {2, 5}; int a[maxn][maxn][2]; int d[maxn][maxn][2]; char path[maxn][maxn][2], s[maxn << 1];
int main() { int n; scanf("%d", &n); bool flag = false; int posx = 0, posy = 0; for (int i = 1; i <= n; ++i) { for (int j = 1; j <= n; ++j) { int x; scanf("%d", &x); if (x == 0) { a[i][j][0] = a[i][j][1] = inf; posx = i, posy = j; flag = true; continue; } for (int k = 0; k < 2; ++k) { while (x % fac[k] == 0) { x /= fac[k]; ++a[i][j][k]; } } } } for (int i = 1; i <= n; ++i) { d[0][i][0] = d[i][0][0] = d[0][i][1] = d[i][0][1] = inf; } d[1][1][0] = a[1][1][0], d[1][1][1] = a[1][1][1]; for (int i = 1; i <= n; ++i) { for (int j = 1; j <= n; ++j) { if (i == 1 && j == 1) continue; for (int k = 0; k < 2; ++k) { if (d[i - 1][j][k] > d[i][j - 1][k]) { d[i][j][k] = d[i][j - 1][k] + a[i][j][k]; path[i][j][k] = 'R'; } else { d[i][j][k] = d[i - 1][j][k] + a[i][j][k]; path[i][j][k] = 'D'; } } } } int ans = d[n][n][0] > d[n][n][1] ? 1 : 0; if (flag && d[n][n][ans] >= 1) { puts("1"); for (int i = 1; i < posx; ++i) { putchar('D'); } for (int i = 1; i < posy; ++i) { putchar('R'); } for (int i = posx; i < n; ++i) { putchar('D'); } for (int i = posy; i < n; ++i) { putchar('R'); } puts(""); return 0; } printf("%dn", d[n][n][ans]); int len = (n - 1) << 1, x = n, y = n; while (len) { s[--len] = path[x][y][ans]; if (s[len] == 'D') { --x; } else { --y; } } puts(s); return 0; }
|