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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章