CodeForces 2B The least round way(dp+数学)

题意:

给你一个矩阵,让你在里面找一条路径,使得这条路径上的数相乘之后的末尾0
最少。
一看像是一个dp的题,但是还是需要一点数学在里面(数学渣伤不起),末尾
0最少,意味着路径上的数的25因子要尽量少,所以我们需要找两条路,一条
是2最少的,一条是5最少的,那么答案就是min(a,b),为什么呢?我们设想一
下,2最少的那条路保证了其他路上的的2都比这个多,5也是同理,又因为这
两条路一般不会是一条,那么对应的路上的25肯定不是最少的,所以答案
出来了。所以这个问题就转化成一个dag上的最短路了,bfs就行。
然而这个题目还是有坑的,因为可能会输入0,这也就意味着连乘之后都是0,
所以,我们需要看一下有0的特殊情况下,答案是1,还要和另外两个比较。 

代码:

//
//  Created by  CQU_CST_WuErli
//  Copyright (c) 2016 CQU_CST_WuErli. All rights reserved.
//
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <queue>
#include <stack>
#include <set>
#include <algorithm>
#include <sstream>
#include <assert.h>
#define CLR(x) memset(x,0,sizeof(x))
#define OFF(x) memset(x,-1,sizeof(x))
#define MEM(x,a) memset((x),(a),sizeof(x))
#define BUG cout << "I am here" << endl
#define lookln(x) cout << #x << "=" << x << endl
#define SI(a) scanf("%d",&a)
#define SII(a,b) scanf("%d%d",&a,&b)
#define SIII(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define rep(flag,start,end) for(int flag=start;flag<=end;flag++)
#define Rep(flag,start,end) for(int flag=start;flag>=end;flag--)
#define Lson l,mid,rt<<1
#define Rson mid+1,r,rt<<1|1
#define Root 1,n,1
#define BigInteger bign
const int MAX_L=2005;// For BigInteger
const int INF_INT=0x3f3f3f3f;
const long long INF_LL=0x7fffffff;
const int MOD=1e9+7;
const double eps=1e-9;
const double pi=acos(-1);
typedef long long  ll;
using namespace std;

const int N=1010;

int a[N][N];
int mp[2][N][N];
int n;
int dp[2][N][N];
char pre[2][N][N];
int vis[N][N];

struct Sta
{
    int x,y;
};

int main(int argc, char const *argv[]) {
#ifdef LOCAL
    freopen("C:\\Users\\john\\Desktop\\in.txt","r",stdin);
    // freopen("C:\\Users\\john\\Desktop\\out.txt","w",stdout);
#endif
    while(SI(n)==1) {
        CLR(mp);
        int flag=0;
        Sta zero;
        rep(i,1,n) rep(j,1,n) {
            int x;SI(x);
            a[i][j]=x;
            int tmp=x;
            if (x==0) {
                zero.x=i;zero.y=j;
                flag=1;
                continue;
            }
            while (tmp%2==0) mp[0][i][j]++,tmp/=2;
            while (x%5==0) mp[1][i][j]++,x/=5;
        }
        int dir[2][2]={1,0,0,1};
        for (int z=0;z<2;z++) for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) dp[z][i][j]=INF_INT;
        for (int z=0;z<2;z++) {
            CLR(vis);CLR(pre[z]);
            queue<Sta> q;
            vis[1][1]=1;
            q.push(Sta{1,1});
            dp[z][1][1]=mp[z][1][1];
            while (q.size()) {
                Sta now=q.front();q.pop();
                for (int i=0;i<2;i++) {
                    int nx=now.x+dir[i][0],ny=now.y+dir[i][1];
                    if (nx<1 || ny<1 || nx>n || ny>n) continue;
                    if (dp[z][nx][ny]>dp[z][now.x][now.y]+mp[z][nx][ny]) {
                        dp[z][nx][ny]=dp[z][now.x][now.y]+mp[z][nx][ny];
                        pre[z][nx][ny]=i==0?'D':'R';
                        if (!vis[nx][ny]) {
                            vis[nx][ny]=1;
                            q.push(Sta{nx,ny});
                        }
                    }
                }
            }
        }
        vector<char> ans;
        if (flag && min(dp[0][n][n],dp[1][n][n])>1) {
            cout << 1 << endl;
            int aa=zero.x,bb=zero.y;
            for (int i=1;i<aa;i++) ans.push_back('D');
            for (int i=1;i<bb;i++) ans.push_back('R');
            for (int i=aa+1;i<=n;i++) ans.push_back('D');
            for (int i=bb+1;i<=n;i++) ans.push_back('R');
            for (int i=0;i<ans.size();i++) cout << ans[i];
            cout << endl;
        }
        else {
            cout << min(dp[0][n][n],dp[1][n][n]) << endl;
            int pos=dp[0][n][n]<dp[1][n][n]?0:1;
            int nx=n,ny=n;
            while(1) {
                ans.push_back(pre[pos][nx][ny]);
                if (pre[pos][nx][ny]=='D') {
                    nx--;
                }
                else ny--;
                if (nx==1 && ny==1) break;
            }
            reverse(ans.begin(),ans.end());
            for (int i=0;i<ans.size();i++) cout << ans[i];
            cout << endl;
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值