最少末尾0的个数

题意:
给定一个二维数组,求从左上角走到右下角得到的数,末尾0的个数最小值(每次向右或向下,边走边乘)


对于任意一条路径,尾0的个数是该路径上cnt2与cnt5之中的较小值,min(cnt2,cnt5)
那就分别对2和5求一遍简单DP,最后再取最小


#include<bits/stdc++.h>
using namespace std;
using ll = long long;
#define dbg(x) cout << #x << "=" << x << endl;
//#define int ll
// DP : 求从(1,1) 到 (n,n) 的路径乘积数目中末尾0的个数最小的数目
// 求2,5的因子数目的最小值
// 对于求得的某一条路径,如果是2最小路径,这条路不可能存在5的数目更大,否则答案在取min的时候会取5最小路径
// 所以对2和5分别进行简单的DP最终取min
int b[1005][1005][2];
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(nullptr), cout.tie(nullptr);
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            int x,x1;
            cin >> x;
            x1 = x;
            while (x%2 == 0) {b[i][j][0]++;x/=2;}
            while (x1%5 == 0) {b[i][j][1]++;x1/=5;} 
        }
    }
    for (int k = 0; k <= 1; k++) {
        for (int i = 1; i <= n; i++) {
            b[1][i][k] += b[1][i-1][k];
            b[i][1][k] += b[i - 1][1][k];
        }
    }
    for (int k = 0; k <= 1; k++) {
        for (int i = 2; i <= n; i++) {
            for (int j = 2; j <= n; j++) {
                b[i][j][k] += min(b[i-1][j][k],b[i][j-1][k]);
            }
        } 
    }
    cout << min(b[n][n][0],b[n][n][1]);
    return 0;
}
github