题目链接:点我
题意:有一个n*n的图,每个位置都有一个非负数值。现在你想从左上角到达右下角,每次只能向下或向右走,已知数值为0的点不能走。我们累乘所走过位置的数值,得到一个数T。问T末尾连续0的个数最少是多少?
思路:因为2*5 = 10得到一个0。我们先预处理质因子5的个数,从左上角到右下角跑一次dp,求出T中最少的5的个数ans1。然后预处理质因子2的个数,再跑一次dp,求出T中最少的2的个数ans2。答案就是min(ans1, ans2)。
AC代码:
#include <cstdio> #include <cstring> #include <algorithm> #define MAXN 1001 #define INF 0x3f3f3f3f using namespace std; int val[MAXN][MAXN]; int dp[MAXN][MAXN]; int Map[MAXN][MAXN]; int main() { int n; while(scanf("%d", &n) != EOF) { for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) scanf("%d", &Map[i][j]); for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { if(Map[i][j] == 0) val[i][j] = INF; else { int cnt = 0; int num = Map[i][j]; while(num % 5 == 0) cnt++, num /= 5; val[i][j] = cnt; } } } memset(dp, INF, sizeof(dp)); dp[1][1] = val[1][1]; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) dp[i][j] = min(dp[i][j], min(dp[i-1][j], dp[i][j-1])+val[i][j]); int ans = dp[n][n]; for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { if(Map[i][j] == 0) val[i][j] = INF; else { int cnt = 0; int num = Map[i][j]; while(num % 2 == 0) cnt++, num /= 2; val[i][j] = cnt; } } } memset(dp, INF, sizeof(dp)); dp[1][1] = val[1][1]; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) dp[i][j] = min(dp[i][j], min(dp[i-1][j], dp[i][j-1])+val[i][j]); ans = min(ans, dp[n][n]); printf("%d\n", ans); } return 0; }