CodeForces - 2B The least round way【dp】

传送门

vjudge上友善的中文题意

分析

后缀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;
}

猜你喜欢

转载自blog.csdn.net/CQBZLYTina/article/details/81450299