1000*1000的方阵,每个格子有一个非负整数,现在要从左上走到右下,每次只能向下或者向右走。目标是使得所有走的格子里的数的乘积里,末尾0的个数最少,要求输出最有解和走法。
不用怎么想也知道基本是个dp了,可以发现其实只有2和5的因子是有用的,但是如果状态同时记录2和5的因子个数的话,就不好表示了。其实方法很简单,对2个5分别做一次,第一次让2尽量少,第二次让5尽量少,两个里面取个最小的就是答案了,应该不难证明。dp过程就比较普通了,记录下路径,最后输出即可,不再赘述。
当然,本题是有一个比较大的trick的,就是如果其中有一个数字为0,那么最后的乘积可以为0,也就是答案至少可以是1。因此,只要先记录下方阵中有没有0,然后dp的时候强制不走0,最后输出走0和不走0的最优解即可。
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 1024;
int m2[MAXN][MAXN];
int m5[MAXN][MAXN];
int l2[MAXN][MAXN];
int l5[MAXN][MAXN];
int dp2[MAXN][MAXN];
int dp5[MAXN][MAXN];
int n;
int zx, zy;
void output(int ll[MAXN][MAXN], int x, int y)
{
if (x == 0 && y == 0)
return;
if (ll[x][y] == 0)
{
output(ll, x - 1, y);
putchar('D');
}
else
{
output(ll, x, y - 1);
putchar('R');
}
}
int main()
{
scanf("%d", &n);
zx = zy = -1;
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
scanf("%d", &m2[i][j]);
if (m2[i][j] != 0)
{
m5[i][j] = 0;
while (m2[i][j] % 5 == 0)
{
++m5[i][j];
m2[i][j] /= 5;
}
int t = 0;
while (m2[i][j] % 2 == 0)
{
++t;
m2[i][j] /= 2;
}
m2[i][j] = t;
}
else
{
zx = i;
zy = j;
m2[i][j] = m5[i][j] = -1;
}
}
}
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
if (m2[i][j] == -1)
dp2[i][j] = -1;
else
{
if (i == 0 && j == 0)
dp2[i][j] = m2[i][j];
else
{
dp2[i][j] = 100000000;
if (i > 0 && dp2[i - 1][j] != -1 && dp2[i - 1][j] + m2[i][j] < dp2[i][j])
{
dp2[i][j] = dp2[i - 1][j] + m2[i][j];
l2[i][j] = 0;
}
if (j > 0 && dp2[i][j - 1] != -1 && dp2[i][j - 1] + m2[i][j] < dp2[i][j])
{
dp2[i][j] = dp2[i][j - 1] + m2[i][j];
l2[i][j] = 1;
}
if (dp2[i][j] == 100000000)
dp2[i][j] = -1;
}
}
}
}
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
if (m5[i][j] == -1)
dp5[i][j] = -1;
else
{
if (i == 0 && j == 0)
dp5[i][j] = m5[i][j];
else
{
dp5[i][j] = 100000000;
if (i > 0 && dp5[i - 1][j] != -1 && dp5[i - 1][j] + m5[i][j] < dp5[i][j])
{
dp5[i][j] = dp5[i - 1][j] + m5[i][j];
l5[i][j] = 0;
}
if (j > 0 && dp5[i][j - 1] != -1 && dp5[i][j - 1] + m5[i][j] < dp5[i][j])
{
dp5[i][j] = dp5[i][j - 1] + m5[i][j];
l5[i][j] = 1;
}
if (dp5[i][j] == 100000000)
dp5[i][j] = -1;
}
}
}
}
if (dp2[n - 1][n - 1] == -1)
{
printf("1\n");
for (int i = 0; i < n - 1; ++i)
putchar('D');
for (int i = 0; i < n - 1; ++i)
putchar('R');
puts("");
}
else
{
int now = min(dp2[n - 1][n - 1], dp5[n - 1][n - 1]);
if (zx != -1 && now >= 1)
{
printf("1\n");
for (int i = 0; i < zx; ++i)
putchar('D');
for (int i = 0; i < n - 1; ++i)
putchar('R');
for (int i = zx; i < n - 1; ++i)
putchar('D');
puts("");
}
else
{
printf("%d\n", now);
if (dp2[n - 1][n - 1] < dp5[n - 1][n - 1])
output(l2, n - 1, n - 1);
else
output(l5, n - 1, n - 1);
puts("");
}
}
return 0;
}
标签:dp5,dp2,--,++,Codeforces,int,Beta,MAXN,m2 From: https://blog.51cto.com/u_16146153/6388585