题目描述
There is a square matrix n×n , consisting of non-negative integer numbers. You should find such a way on it that
starts in the upper left cell of the matrix;
each following cell is to the right or down from the current cell;
the way ends in the bottom right cell.
Moreover, if we multiply together all the numbers along the way, the result should be the least “round”. In other words, it should end in the least possible number of zeros.
输入格式
The first line contains an integer number nn ( 2<=n<=1000 ), nn is the size of the matrix. Then follow n lines containing the matrix elements (non-negative integer numbers not exceeding 10^{9} ).
输出格式
In the first line print the least number of trailing zeros. In the second line print the correspondent way itself.
大体意思就是在一个矩阵中找出一条路径,使得这条路径上的数相乘后得到的乘积的后导0最少——分两种情况:(1)路径中有0;(2)没有0。
首先分析,如果存在后导0,那么乘数的因子一定含有2与5,min(2,5)就是后导0的个数,所以这里进行预处理,分别求每个数2与5的因子个数。
其次状态转移转移方程:f[i][j][k]=min(f[i-1][j][k],f[i][j-1][k])+num[i][j][k]。(f,表示到达(i,j)时最少因子个数;k代表因子是2或5)
最后输出路径:逆DP过程,先判断到(i,j)点是从上方还是从左方到达的,一直递归到初始点,回溯输出路径。
#include <bits/stdc++.h>
//dfs 大法师
using namespace std;
const int mod=20100403;
const int Inf=0x3f3f3f3f;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int n,t,num[1002][1002][2],f[1002][1002][2];
void Print(int i,int j,int k) {
if(i==1&&j==1) { //递归输出函数
putchar(k? 'D':'R');
return ; //边界
}
if(i==1)
Print(i,j-1,0);
else if(j==1)
Print(i-1,j,1);
else if(f[i][j][t]==f[i][j-1][t]+num[i][j][t])
Print(i,j-1,0);
else
Print(i-1,j,1);
if(i!=n||j!=n)
putchar(k? 'D':'R'); //在(n,n)处不输出
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int ans;
scanf("%d",&n);
for(int i=1,k;i<=n;++i)
for(int j=1;j<=n;++j) { //预处理因子个数
scanf("%d",&k);
if(!k) {
num[i][j][0]=num[i][j][1]=1;
t=i; //特判0,记录位置
}
else {
for(;!(k%2);k/=2)
++num[i][j][0];
for(;!(k%5);k/=5)
++num[i][j][1];
}
}
for(int i=1;i<=n;++i)
f[0][i][0]=f[i][0][0]=f[0][i][1]=f[i][0][1]=Inf; //由于转移方程使用min,将边界赋为最大值
f[1][1][0]=num[1][1][0];
f[1][1][1]=num[1][1][1];
for(int k=0;k<2;++k)
for(int i=1;i<=n;++i)
for(int j=i==1? 2:1;j<=n;++j)
f[i][j][k]=min(f[i][j-1][k],f[i-1][j][k])+num[i][j][k];
ans=min(f[n][n][0],f[n][n][1]);
if(t&&ans>1) { //情况2
printf("1\n");
for(int i=1;i<t;++i)
putchar('D');
for(int i=1;i<n;++i)
putchar('R');
for(int i=t;i<n;++i)
putchar('D');
}
else { //情况1
printf("%d\n",ans);
t=!(f[n][n][0]<f[n][n][1]);
Print(n,n,1);
}
return 0;
}