题目链接:CF2B The least round way
显然需要 (dp) 解决。
第一个思路:用 (dp_{i}{j})代表第 (i) 行第 (j) 列最小的后缀 (0) 数,不幸的是,他被 hack 了。
考虑 (10)的形成,贡献只来自于 (2) 和 (5) 这个因数。
我们容易想到最小化 (min{sum a_i,sum b_i})。
ps:(sum a_i) 代表路径中数含有因子 (2) 的数量,(sum b_i) 代表路径中数含有因子 (5) 的数量。
于是我们就有了两个子任务,最小化 (sum a_i) 和 (sum b_i),然后再取 (min)。
这就是两个简单 (dp) 了(我没骗你吧)。
我们记 (dp1_{i,j}) 为到坐标为 ((i,j)) 的点最小的 (sum a_i);
我们记 (dp2_{i,j}) 为到坐标为 ((i,j)) 的点最小的 (sum b_i);
可以得到递推式:
[dp1_{i,j}=min{dp1_{i-1,j},dp1_{i,j-1}}+a_{i,j}
]
[dp2_{i,j}=min{dp2_{i-1,j},dp2_{i,j-1}}+b_{i,j}
]
对于 (a_{i,j}) 和 (b_{i,j}) 是可以直接预处理出来的(每次判断是否整除),这个处理的期望复杂度应该是 (mathcal O(n^2))。
于是我们就能得到一个复杂度为 (mathcal O(n^2)) 的算法。
但是还有个坑:矩阵中的数可能为零,这是 (2) 和 (5) 也没有贡献。
我们只需判断有没有答案为 (0) 的走法(乘积为 (0) 时答案为 (1)),如果不存在,只需找一条经过 (0) 的路线即可。
废话不多说,上代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
#define read(x) scanf("%d",&x)
#define readl(x) scanf("%lld",&x)
#define ll long long
#define inf 2147483647
int n;
int x[1005][1005];
int a[1005][1005],b[1005][1005],dp1[1005][1005],dp2[1005][1005];
int sum1[1005][1005],sum2[1005][1005];
int op1[1005][1005],op2[1005][1005];
int ans[1000005],cnt=0;
int flag=0,xx,yy;
inline int cal(ll n,int a)
{
int ans=0;
while(n%a==0&&n!=0) ans++,n/=a;
return ans;
}
int main()
{
read(n);
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) readl(x[i][j]),dp1[i][j]=inf,dp2[i][j]=inf;
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(x[i][j]==0) flag=1,xx=i,yy=j;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++) a[i][j]=cal(x[i][j],2),b[i][j]=cal(x[i][j],5);
}
dp1[1][1]=a[1][1],sum1[1][1]=b[1][1];
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i==n&&j==n) continue;
if(i<n)
{
if(dp1[i+1][j]>=dp1[i][j]+a[i+1][j])
{
dp1[i+1][j]=dp1[i][j]+a[i+1][j];
op1[i+1][j]=1;
sum1[i+1][j]=sum1[i][j]+b[i+1][j];
}
}
if(j<n)
{
if(dp1[i][j+1]>=dp1[i][j]+a[i][j+1])
{
dp1[i][j+1]=dp1[i][j]+a[i][j+1];
op1[i][j+1]=2;
sum1[i][j+1]=sum1[i][j]+b[i][j+1];
}
}
}
}
dp2[1][1]=b[1][1],sum2[1][1]=a[1][1];
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i==n&&j==n) continue;
if(i<n)
{
if(dp2[i+1][j]>=dp2[i][j]+b[i+1][j])
{
dp2[i+1][j]=dp2[i][j]+b[i+1][j];
op2[i+1][j]=1;
sum2[i+1][j]=sum2[i][j]+a[i+1][j];
}
}
if(j<n)
{
if(dp2[i][j+1]>=dp2[i][j]+b[i][j+1])
{
dp2[i][j+1]=dp2[i][j]+b[i][j+1];
op2[i][j+1]=2;
sum2[i][j+1]=sum2[i][j]+b[i][j+1];
}
}
}
}
if(min(dp1[n][n],dp2[n][n])>=1&&flag)
{
printf("1
");
for(int i=2;i<=yy;i++) putchar('R');
for(int i=2;i<=n;i++) putchar('D');
for(int i=yy+1;i<=n;i++) putchar('R');
}
else if(dp1[n][n]<=dp2[n][n])
{
printf("%d
",min(dp1[n][n],sum1[n][n]));
int x=n,y=n;
while(x+y!=2)
{
if(op1[x][y]==1) ans[++cnt]=1,x-=1;
else ans[++cnt]=2,y-=1;
}
for(int i=cnt;i>=1;i--)
{
if(ans[i]==1) printf("D");
else printf("R");
}
}
else
{
printf("%d
",min(dp2[n][n],sum2[n][n]));
int x=n,y=n;
while(x+y!=2)
{
if(op2[x][y]==1) ans[++cnt]=1,x-=1;
else ans[++cnt]=2,y-=1;
}
for(int i=cnt;i>=1;i--)
{
if(ans[i]==1) printf("D");
else printf("R");
}
}
putchar('
');
return 0;
}