【CF2B The least round way】题解
题目链接
题目
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.
给定由非负整数组成的\(n \times n\) 的正方形矩阵,你需要寻找一条路径:
以左上角为起点
每次只能向右或向下走
以右下角为终点
并且,如果我们把沿路遇到的数进行相乘,积应当是最小“round”,换句话说,应当以最小数目的0的结尾.
思路
要使0结尾最少,也就是要使以2结尾和以5结尾最少,因为0的个数并不是由多的那个因子觉定的,而是由少的那个因子觉定的,所以我们可以看一下从起点到终点2和5最少出现多少次,取个min值就是答案,这个过程可以用dp来实现。
要注意的是,如果出现0,那么必然存在一条道路只有1个0结尾,这时我们就要与前面那种情况作比较,有更优的输出。
总结
一开始做这道题时想的是要把其中一个因子(也就是2或5)的个数压到dp转态中(就是 \(dp(i,j,k)\) 表示在 \((i,j)\) 号格子当5的个数为 \(k\) 时,2的个数最少为 \(dp(i,j,k)\)),类似一种dp的方法,这使我想不出怎么优化。
后来看题解,发现本质上0的个数是由2和5中较少那个数的数量觉定的,这个思路挺妙。其实对于这种题,尤其是背包累,当要存的转态多时,可以看看答案是否有小的那个数量觉定。
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
//#define M
//#define mo
#define N 1010
int n, m, i, j, k;
int a[N][N], dp[N][N][2], f[N][N][2], ans;
void dfs(int x, int y, int k)
{
// printf("%d %d %d\n", x, y, k);
// if(x==1||y==1) return ;
// if(x==1&&y==1) return ;
if(f[x][y][k]==1) dfs(x, y-1, k), putchar('R');
if(f[x][y][k]==-1) dfs(x-1, y, k), putchar('D');
}
signed main()
{
// freopen("tiaoshi.in", "r", stdin);
// freopen("tiaoshi.out", "w", stdout);
memset(dp, 0x3f, sizeof(dp));
dp[0][1][0]=dp[0][1][1]=0;
ans=0x7fffffff;
n=read();
for(i=1; i<=n; ++i)
for(j=1; j<=n; ++j)
{
a[i][j]=read();
if(!a[i][j]) ans=1;
while(a[i][j]&&a[i][j]%2==0) a[i][j]/=2, ++m;
dp[i][j][0]=min(dp[i-1][j][0], dp[i][j-1][0])+m; m=0;
f[i][j][0]=(dp[i-1][j][0]<dp[i][j-1][0] ? -1 : 1);
while(a[i][j]&&a[i][j]%5==0) a[i][j]/=5, ++m;
dp[i][j][1]=min(dp[i-1][j][1], dp[i][j-1][1])+m; m=0;
f[i][j][1]=(dp[i-1][j][1]<dp[i][j-1][1] ? -1 : 1);
if(i==1&&j==1) f[i][j][0]=f[i][j][1]=0;
// printf("%lld %lld\n", dp[i][j][0], dp[i][j][1]);
}
printf("%lld\n", min(ans, min(dp[n][n][0], dp[n][n][1])));
if(ans<min(dp[n][n][0], dp[n][n][1]))
{
for(i=1; i<=n; ++i)
for(j=1; j<=n; ++j)
if(!a[i][j])
{
for(k=1; k<i; ++k) printf("D");
for(k=1; k<j; ++k) printf("R");
for(k=i; k<n; ++k) printf("D");
for(k=j; k<n; ++k) printf("R");
return 0;
}
}
if(dp[n][n][0]<dp[n][n][1]) dfs(n, n, 0);
else dfs(n, n, 1);
return 0;
}
本文来自博客园,作者:zhangtingxi,转载请注明原文链接:https://www.cnblogs.com/zhangtingxi/p/15720399.html