Codeforces2B - The least round way(DP)

题目大意

给定一个N*N的格子,每个格子里有一个非负数,要求你找出从左上角到右下角的一条路径,使得它满足路径上的格子里的数全部乘起来的积尾部0最少

题解

如果要产生0肯定是2*5得出来的,最终的乘积可以表示为2^x*5^y*C,那么零的个数就是min(x,y)。我们可以先对每个格子里的数预处理下,计算出2和5的个数来,然后DP分别求出2和5的最小个数然后选两者中的最小值,输出路径方法没啥说的,很传统~~还有一个要注意的问题就是如果某个格子的数字为0的情况,这个需要特殊判断一下,我们可以把它当做10,如果最后的结果0的个数大于1则直接输出尾部0的个数为1即可

代码

#include <iostream>

#include <algorithm>

#include <cstdio>

#include <string>

#include <utility>

using namespace std;

#define  MAXN 1005

#define  INF 0x7fffffff

int path[MAXN][MAXN][2];

int dp[MAXN][MAXN][2],a[MAXN][MAXN][2],n;

int zerox,zeroy,x;

string s;

bool flag;

int main()

{

    scanf("%d",&n);

    flag=false;

    for(int i=0;i<n;i++)

        for(int j=0;j<n;j++)

        {

            scanf("%d",&x);

            if(!x)

            {     

                a[i][j][0]=a[i][j][1]=1;

                zerox=i,zeroy=j,flag=true;

            }

            else

            {

                while(x%2==0) {a[i][j][0]++;x/=2;}

                while(x%5==0) {a[i][j][1]++,x/=5;}

            }

        }

        for(int k=0;k<2;k++)

            for(int i=0;i<n;i++)

                for(int j=0;j<n;j++)

                {

                    int ans=INF;

                    if(i==0&&j==0) ans=0;

                    if(i!=0&&dp[i-1][j][k]<ans) ans=dp[i-1][j][k];

                    if(j!=0&&dp[i][j-1][k]<ans) ans=dp[i][j-1][k],path[i][j][k]=1;

                    dp[i][j][k]=ans+a[i][j][k];

                }

                int k=dp[n-1][n-1][0]<dp[n-1][n-1][1]?0:1;

                if(flag&&dp[n-1][n-1][k]>1)

                {

                    for(int i=0;i<zeroy;i++)

                        s+="R";

                    for(int i=0;i<zerox;i++)

                        s+="D";

                    for(int i=0;i<n-zeroy-1;i++)

                        s+="R";

                    for(int i=0;i<n-zerox-1;i++)

                        s+="D";

                    cout<<1<<endl<<s<<endl;

                }

                else

                {

                    int i=n-1,j=n-1;

                    while(i>0||j>0)

                    {

                        if(path[i][j][k]==1)

                            s+="R",j--;

                        else

                            s+="D",i--;

                    }

                    reverse(s.begin(),s.end());

                    cout<<dp[n-1][n-1][k]<<endl<<s<<endl;

                }

                return 0;

}

你可能感兴趣的:(codeforces)