The least round way | CF2B
2000
2000
2000 分 给定
n
×
n
n\times n
n×n 的矩阵,数字
a
i
,
j
a_{i,j}
ai,j 开始在左上角,每次向下 / 向右走一格,走大右下角,求所有数字的乘积的末尾
0
0
0 的个数的最小值 你需要输出这样的一条路径
1
≤
n
≤
1
0
3
1\le n\le 10^3
1≤n≤103
0
≤
a
i
,
j
≤
1
0
9
0\le a_{i,j}\le 10^9
0≤ai,j≤109
思路
题目可以转化为,每个位置有
2
2
2 的因子的个数
a
a
a 个,有
5
5
5 的因子的个数
b
b
b 个 你需要走一条路,让
min
{
∑
a
,
∑
b
}
\min\{\sum_a,\sum_b\}
min{∑a,∑b} 最小 之前的题是让
∑
a
×
∑
b
\sum_a\times\sum_b
∑a×∑b 最大,感觉稍微有点题意类似吧…
貌似直接搞不是很好做,但是我们可以把原问题化成两个子问题:
d
p
1
[
i
]
[
j
]
dp1[i][j]
dp1[i][j] 表示走到
(
i
,
j
)
(i,j)
(i,j) 的
min
{
∑
a
}
\min\{\sum_a\}
min{∑a}
d
p
2
[
i
]
[
j
]
dp2[i][j]
dp2[i][j] 表示走到
(
i
,
j
)
(i,j)
(i,j) 的
min
{
∑
b
}
\min\{\sum_b\}
min{∑b} 最后答案就是
min
{
d
p
1
[
n
]
[
n
]
,
d
p
2
[
n
]
[
n
]
}
\min\{dp1[n][n],dp2[n][n]\}
min{dp1[n][n],dp2[n][n]}
诶?我 们 可能会怀疑,路径只能走一条,但是你求
∑
a
\sum_a
∑a 最小值的路可能和求
∑
b
\sum_b
∑b 最小值的路是不同的,怎么会合法呢? 但是仔细一想,因为我们的答案一定为
min
{
d
p
1
[
n
]
[
n
]
,
d
p
2
[
n
]
[
n
]
}
\min\{dp1[n][n],dp2[n][n]\}
min{dp1[n][n],dp2[n][n]} ,因此要么
∑
a
\sum_a
∑a 取到最小值(此时不管
∑
b
\sum_b
∑b 多大我们的答案都不变),要么 相反的情况 所以我们用
f
a
[
i
]
[
j
]
[
2
]
fa[i][j][2]
fa[i][j][2] 记录两种道路的前驱,就可以去走了
当然题目还有坑,那就是有可能
a
i
,
j
=
0
a_{i,j}=0
ai,j=0 因为是数字乘积,走到
0
0
0 当然中间不管怎么走我们最后的答案都是
1
1
1 了,最后和我们之前的答案特判一下哪个小即可 注意还有一个坑点 (但是没有注意到这个也能过,样例水了),我们之前求
∑
a
\sum_a
∑a 的路上,如果遇到了
0
0
0 ,那么明显最后值为
0
0
0 了,所以对于所有值为
0
0
0 的点,我们让它们位置的
a
=
inf
,
b
=
inf
a=\inf,b=\inf
a=inf,b=inf,不然可以有
H
a
c
k
Hack
Hack 样例的:
3220505022/**
应该输出 1,但是不修改则会输出 0
*/
代码
时间复杂度:
O
(
n
2
)
O(n^2)
O(n2)
#include<bits/stdc++.h>#defineIOSios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;typedeflonglong ll;voidshow(){std::cerr << endl;}template<typename T,typename... Args>voidshow(T x,Args... args){std::cerr <<"[ "<< x <<" ] , ";show(args...);}constint MAX =1e3+50;constint MOD =1e9+7;constint INF =0x3f3f3f3f;const ll LINF =0x3f3f3f3f3f3f3f3f;constdouble EPS =1e-5;int dp[MAX][MAX][2];int shu[MAX][MAX][2];int fa[MAX][MAX][2];
bool zero;int zx,zy;intmain(){int n;n =read();for(int i =0;i <= n;++i)for(int j =0;j <= n;++j)
dp[i][j][0]= dp[i][j][1]= INF;for(int i =1;i <= n;++i)for(int j =1;j <= n;++j){int t =read();if(t ==0){
zero = true;
zx = i;
zy = j;
shu[i][j][0]= INF;
shu[i][j][1]= INF;continue;}while(t %2==0){
shu[i][j][0]++;
t /=2;}while(t %5==0){
shu[i][j][1]++;
t /=5;}}
dp[0][1][0]= dp[0][1][1]=0;for(int i =1;i <= n;++i)for(int j =1;j <= n;++j){
dp[i][j][0]=min(dp[i-1][j][0],dp[i][j-1][0])+ shu[i][j][0];
dp[i][j][1]=min(dp[i-1][j][1],dp[i][j-1][1])+ shu[i][j][1];if(dp[i-1][j][0]< dp[i][j-1][0])fa[i][j][0]=1;else fa[i][j][0]=2;if(dp[i-1][j][1]< dp[i][j-1][1])fa[i][j][1]=1;else fa[i][j][1]=2;}int ans =min(dp[n][n][0],dp[n][n][1]);int op = dp[n][n][0]< dp[n][n][1]?0:1;if(zero && ans >1){
cout <<1<< endl;for(int i =1;i < zx;++i)cout <<"D";for(int i =1;i < zy;++i)cout <<"R";for(int i = zx;i < n;++i)cout <<"D";for(int i = zy;i < n;++i)cout <<"R";return0;}else{
stack<char>S;int x = n,y = x;while(1){if(fa[x][y][op]==2){
S.push('R');
y--;}else{
S.push('D');
x--;}if(x ==1&& y ==1)break;}
cout << ans << endl;while(!S.empty()){
cout << S.top();
S.pop();}}return0;}