题解 CF2B 【The least round way】

· · 题解

个人感觉难度位于普及+/提高,不然我这个菜鸡咋做的出来

做法:

这是一道动态规划题。

既然想要末尾最少个 0,那么组成末尾 0 的唯一办法只有 2\times5,所以末尾 0 的个数就等于因子 2 的个数与因子 5 的个数的最小值。

先分别获取该数因子 2 的个数和因子 5 的个数,预处理出 dp[i][j] 处是 dp[i-1][j] 大还是 dp[i][j-1] 大,最后再递归输出。

特判:

如果存在 0[n,n] 位置 25 较小的个数大于一的话,从起点一直下到有 0 的那一行,直接走完那一行后一直往下到达终点。

提示:

$dp[i][j][1]$ 表示走到当前 $[i,j]$ 位置的因子 $5$ 的个数。 $big[i][j]$ 表示递归输出时往上好还是往左好。 $x$ 为记录有 $0$ 的那一行。 ## Code: ``` C++ #include<bits/stdc++.h> using namespace std; const int N = 1010; const int INF = 1000100101; int dp[N][N][2]; int x = -1,k; bool big[N][N][2]; void out(int x,int y) { if(x == 1 && y == 1) { return; } if(big[x][y][k] == false){ out(x,y - 1); printf("R"); } else { out(x - 1,y); printf("D"); } } int main() { int n; scanf("%d",&n); int i,j; for(i = 2;i <= n;i++){ dp[i][0][0] = dp[0][i][0] = INF; dp[i][0][1] = dp[0][i][1] = INF; } for(i = 1;i <= n;i++) { for(j = 1;j <= n;j++){ scanf("%d",&k); if(k == 0) { x = i; } else { while(k % 2 == 0) { dp[i][j][0]++; k /= 2; } while(k % 5 == 0) { dp[i][j][1]++; k /= 5; } } for(int x = 0;x < 2;x++){ if(dp[i-1][j][x] < dp[i][j-1][x]) { dp[i][j][x] += dp[i-1][j][x]; big[i][j][x] = true; } else { dp[i][j][x] += dp[i][j-1][x]; big[i][j][x] = false; } } } } k = 0; if (dp[n][n][0] > dp[n][n][1]) { k = 1; } if(x != -1 && dp[n][n][k] > 1){ puts("1"); for(i = 1;i < x;i++) { printf("D"); } for(i = 1;i < n;i++) { printf("R"); } for(i = x;i < n;i++) { printf("D"); } return 0; } printf("%d\n",dp[n][n][k]); out(n,n); return 0; } ```