CodeForces - 2B The least round way【dp】
分析
后缀0代表该数是10的倍数,应由若干2*5产生
我们把每个格子里的数因数分解预处理出它包含的2和5的数量
而10的个数,为2的个数和5的个数取min
dp[i][j][k] =min(dp[i][j-1][k],dp[i-1][j][k])
k=0:2
k=1:5
存在0的话 把0看成10 即只有一个末尾的0
如果本身存在末尾没有0的路径 则不会产生影响
否则的话,就是走0的那条路末尾0最少,只有1个
当然,由于把0看成了10,那么经过了0的路径的状态如果有其它的2和5都是错的,因为走了0末尾就只有1个
那这么说来只要把0看成10的倍数随便什么都可以 并不会影响答案
输出路径的话 好麻烦啊 写了好久qwq 还是用了递归输出
用pre[i][j][k]记录(i,j) 的上一个节点,1表示左边,0表示上面
其实也不难理解
然后WA了两次 发现主函数的tmp原来命名为x,重名了… 改了就A了 我居然会犯这种错误qwq
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define MAXN 1005
#define INF 0x3f3f3f3f
int a[MAXN][MAXN][2],dp[MAXN][MAXN][2],n,pre[MAXN][MAXN][2];
vector<char> an;
void DP()
{
memset(dp,INF,sizeof(dp));
dp[1][1][0]=dp[1][1][1]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=0;k<=1;k++)
{//注意判越界,也可以将边界0的那些部分赋成INF,然后除(1,1)外其它可以正常转移
if(i-1)
{
dp[i][j][k]=min(dp[i][j][k],dp[i-1][j][k]);
if(dp[i][j][k]==dp[i-1][j][k]) pre[i][j][k]=0;
}
if(j-1)
{
dp[i][j][k]=min(dp[i][j][k],dp[i][j-1][k]);
if(dp[i][j][k]==dp[i][j-1][k]) pre[i][j][k]=1;
}
dp[i][j][k]+=a[i][j][k];
}
}
void print(int x,int y,int k)
{
if(x==1&&y==1) return ;
if(pre[x][y][k]==0)
{
print(x-1,y,k);
printf("D");
}
else
{
print(x,y-1,k);
printf("R");
}
}
int main()
{
scanf("%d",&n);
int x=0,y=0;
bool f=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
int tmp;
scanf("%d",&tmp);
if(tmp==0)
{
f=1;
x=i,y=j;
a[i][j][0]=a[i][j][1]=1;
continue;
}
while(tmp%2==0)
{
tmp/=2;
a[i][j][0]++;
}
while(tmp%5==0)
{
tmp/=5;
a[i][j][1]++;
}
}
DP();
int ans=min(dp[n][n][0],dp[n][n][1]);
if(f&&ans>=1)
{
printf("1\n");
for(int i=1;i<x;i++) printf("D");
for(int i=1;i<y;i++) printf("R");
for(int i=x;i<n;i++) printf("D");
for(int i=y;i<n;i++) printf("R");
return 0;
}
printf("%d\n",ans);
if(dp[n][n][0]<dp[n][n][1])
print(n,n,0);
else print(n,n,1);
return 0;
}
转载请注明出处,有疑问欢迎探讨
博主邮箱 2775182058@qq.com