题目传送门
题意:
n*n的矩阵,每个格子有一个非负整数。起点在左上角的格子,每次移动可以向下或向右。不能越界。终点是右下角的格子。
把路径上的数乘起来,使乘积的后导0个数最少。0认为有一个后导0。
数据范围: , 。 是矩阵上的数。
题解:
从起点到终点路径上的数的乘积因子中2的个数设为x,5的个数设为y。如果不考虑0,答案就是min(x,y)。
如果路径上有0,那么后导0个数为1,需特判。
这道题的2因子和5因子是独立的。意识到这点就完了。
假设x的最小值是minx,y的最小值是miny。
设从起点到终点路径上2的因子数是minx时,5的因子数是y。那么(minx,y)是有关的二元组。
设从起点到终点路径上5的因子数是miny时,2的因子数是x。那么(x,miny)是有关的二元组。
不妨设minx<miny,那么这个时候minx < miny <= y。容易知道路径上后导0个数是minx。
然后dp并记录路径就好了。
感受:
这道题真的把我educate了。
这道题一直WA在变量名写重了。前面那么多测例没WA是因为在第31个测例才用到写重的部分。
代码:
#include<bits/stdc++.h>
using namespace std ;
const int maxn = 1005 ;
const int inf = 0x3f3f3f3f ;
int n ;
int num[maxn][maxn][2] ;
int dp[maxn][maxn][2] , p[maxn][maxn][2] ;
void change(int a , int b , int c , int d , int id , int f)
{
int x = dp[a][b][id] + num[c][d][id] ;
int y = dp[c][d][id] ;
if(x < y)
{
dp[c][d][id] = x ;
p[c][d][id] = f ;
}
}
void dfs(int x , int y , int id)
{
if(x == 1 && y == 1) return ;
if(p[x][y][id] == 0) dfs(x - 1 , y , id) ;
else dfs(x , y - 1 , id) ;
if(p[x][y][id] == 0) printf("D") ;
else printf("R") ;
}
void solve(bool flag , int x , int y)
{
int ans = inf ;
if(flag) ans = 1 ;
dp[1][1][0] = num[1][1][0] ;
dp[1][1][1] = num[1][1][1] ;
for(int i = 1 ; i <= n ; i ++)
for(int j = 1 ; j <= n ; j ++)
{
change(i , j , i + 1 , j , 0 , 0) ;
change(i , j , i + 1 , j , 1 , 0) ;
change(i , j , i , j + 1 , 0 , 1) ;
change(i , j , i , j + 1 , 1 , 1) ;
}
int z = min(dp[n][n][0] , dp[n][n][1]) ;
if(z >= ans)
{
printf("1\n") ;
for(int i = 1 ; i <= x - 1 ; i ++) printf("D") ;
for(int i = 1 ; i <= y - 1 ; i ++) printf("R") ;
for(int i = 1 ; i <= n - x ; i ++) printf("D") ;
for(int i = 1 ; i <= n - y ; i ++) printf("R") ;
printf("\n") ;
}
else
{
printf("%d\n" , z) ;
if(dp[n][n][0] < dp[n][n][1]) dfs(n , n , 0) ;
else dfs(n , n , 1) ;
printf("\n") ;
}
}
int main()
{
bool flag = 0 ;
int x = 0 , y = 0 ;
scanf("%d" , &n) ;
memset(num , 0 , sizeof(num)) ;
memset(dp , inf , sizeof(dp)) ;
for(int i = 1 ; i <= n ; i ++)
for(int j = 1 ; j <= n ; j ++)
{
int z ;
scanf("%d" , &z) ;
if(z == 0) flag = 1 , x = i , y = j ;
else
{
while(z % 2 == 0) z /= 2 , num[i][j][0] ++ ;
while(z % 5 == 0) z /= 5 , num[i][j][1] ++ ;
}
}
solve(flag , x , y) ;
return 0 ;
}