CodeForces2 B.The least round way (dp)

题意:

给一个n2的矩阵a,矩阵中的每一个数a(i,j)在0到1e9之间,
现在要找一条从(1,1)到(n,n)的路径,使得路径上数的乘积结果末尾的0数量最少
输出最小值以及路径

思路:

总所周知,末尾0的个数只与质因子中2和5的个数有关,为2和5数量中的较小值。
所以把数拆成2和5,分开dp:
d(i,j,0)表示到(i,j)处最少的2的个数
d(i,j,1)表示到(i,j)处最少的5的个数
答案就是d(n,n,0)与d(n,n,1)中的较小值
dp过程中记录路径即可

但是这样还不够,因为矩阵中的数可能为0,如果走有0的位置,那么最后的乘积肯定是0,末尾0的个数就是1。
如果正常dp得出的结果大于1,且矩阵中有0,那么就随便构造一条经过这个0的路径,这样更优。

ps:
不太明白为什么不能把2和5合在一起考虑,wa13。
拆成min(2的个数)和min(5的个数)两次dp才能过。

code:

#include<bits/stdc++.h>
using namespace std;
const int maxm=1e3+5;
int a[maxm][maxm][2];
int d[maxm][maxm][2];
char pre[maxm][maxm][2];
signed main(){
    int n;
    scanf("%d",&n);
    int flag=0;
    int posx,posy;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            int x;
            scanf("%d",&x);
            if(!x){
                posx=i,posy=j,flag=1;
                continue;
            }
            while(x%2==0){
                a[i][j][0]++;
                x/=2;
            }
            while(x%5==0){
                a[i][j][1]++;
                x/=5;
            }
        }
    }
    for(int i=1;i<=n;i++){//初始化
        for(int j=1;j<=n;j++){
            d[i][j][0]=d[i][j][1]=1e9;
        }
    }
    d[1][1][0]=a[1][1][0];
    d[1][1][1]=a[1][1][1];
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(j+1<=n){
                if(d[i][j][0]+a[i][j+1][0]<d[i][j+1][0]){
                    d[i][j+1][0]=d[i][j][0]+a[i][j+1][0];
                    pre[i][j+1][0]='L';
                }
                if(d[i][j][1]+a[i][j+1][1]<d[i][j+1][1]){
                    d[i][j+1][1]=d[i][j][1]+a[i][j+1][1];
                    pre[i][j+1][1]='L';
                }
            }
            if(i+1<=n){
                if(d[i][j][0]+a[i+1][j][0]<d[i+1][j][0]){
                    d[i+1][j][0]=d[i][j][0]+a[i+1][j][0];
                    pre[i+1][j][0]='U';
                }
                if(d[i][j][1]+a[i+1][j][1]<d[i+1][j][1]){
                    d[i+1][j][1]=d[i][j][1]+a[i+1][j][1];
                    pre[i+1][j][1]='U';
                }
            }
        }
    }
    if(flag&&d[n][n][0]>1&&d[n][n][1]>1){//有0走0的话,答案为1
        string ans;
        for(int i=1;i<posx;i++)ans+='D';
        for(int i=1;i<posy;i++)ans+='R';
        for(int i=1;i<n-posx+1;i++)ans+='D';
        for(int i=1;i<n-posy+1;i++)ans+='R';
        cout<<1<<endl;
        cout<<ans<<endl;
        return 0;
    }
    if(d[n][n][0]<d[n][n][1])flag=0;
    else flag=1;
    cout<<d[n][n][flag]<<endl;
    int x=n,y=n;
    string ans;
    while(x!=1||y!=1){
        if(pre[x][y][flag]=='L')ans+='R',y--;
        else ans+='D',x--;
    }
    reverse(ans.begin(),ans.end());
    cout<<ans<<endl;
    return 0;
}

发布了430 篇原创文章 · 获赞 36 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/104688247