zoukankan      html  css  js  c++  java
  • 数论+dp Codeforces Beta Round #2 B

    http://codeforces.com/contest/2/problem/B

    题目大意:给你一个n*n的矩形,问从(1,1)出发到(n,n),把图中经过的所有的数字都乘在一起,最后这个数字有多少个0?

    思路:经过分析,只有2和5出现的时候才会有0.所以我们预处理把这个数包含的所有的2和5都给拿出来就好了。但是我发现如果每次转移都要统计2和5的个数的话,状态就炸了,所以我只想到了这里TAT。后来看了一下题解以后发现,只需要知道目前到这个位置以后最小的2(或5)的个数就好了。

    然后转移我也想了好半天。。。于是还是看了。。。2333(我好菜啊)

    转移就是只需要知道最后最小的个数是2还是5,然后再通过该数字去转移就好了

    于是早上+中午+下午3个小时就过去了= =

    //看看会不会爆int!数组会不会少了一维!
    //取物问题一定要小心先手胜利的条件
    #include <bits/stdc++.h>
    using namespace std;
    #define LL long long
    #define ALL(a) a.begin(), a.end()
    #define pb push_back
    #define mk make_pair
    #define fi first
    #define se second
    #define haha printf("haha
    ")
    const int maxn = 1000 + 5;
    const LL inf = 1e17;
    LL a[maxn][maxn];
    pair<LL, LL> p[maxn][maxn];
    LL dp[maxn][maxn][2];
    int n;
    /*
    定义dp[i][j]表示到(i,j)所经过的0的最少的个数
    0只在2*5的时候出现,所以只需要统计2和5的个数即可
    以上思路是行不通的,因为这样子的话dfs或者dp都会有两个变量,所以会超级难写(TAT我写了一个早上)
    所以我们要找一下两者当中的共同点。我们只需要找目前状态的2或5的最大值就好了
    */
    pair<LL, LL> cal(LL val){
        pair<LL, LL> cnt = mk(0, 0);
        LL tmp = val;
        while (val % 2 == 0 && val) {cnt.fi++; val /= 2;}
        val = tmp;
        while (val % 5 == 0 && val) {cnt.se++; val /= 5;}
        return cnt;
    }
    vector<char> v;
    
    bool dfs(int x, int y, int k){///0 is first, 1 is second
        //printf("x = %d y = %d
    ", x, y);
        if (x > n || y > n || x < 1 || y < 1) return false;
        if (x == 1 && y == 1) return true;
        if (dp[x - 1][y][k] < dp[x][y - 1][k]){
            if (dfs(x - 1, y, k)) {v.push_back('D'); return true;}
        }
        else {
            if (dfs(x, y - 1, k)) {v.push_back('R'); return true;}
        }
        return false;
    }
    
    int main(){
        cin >> n;
        memset(p, -1, sizeof(p));
        bool flag = false;
        pair<int, int> zero;
        for (int i = 1; i <= n; i++){
            for (int j = 1; j <= n; j++){
                scanf("%lld", &a[i][j]);
                p[i][j] = cal(a[i][j] == 0 ? 10 : a[i][j]);///当做10,先消去0的影响
                if (a[i][j] == 0) {flag = true; zero = mk(i, j);}
            }
        }
        for (int i = 0; i <= n; i++)
            for (int j = 0; j <= n; j++){
                for (int k = 0; k < 2; k++)
                    dp[i][j][k] = inf;
                if (p[i][j].fi == -1) p[i][j] = mk(inf, inf);
            }
        dp[1][1][0] = p[1][1].fi, dp[1][1][1] = p[1][1].se;
        for (int i = 1; i <= n; i++){
            for (int j = 1; j <= n; j++){
                if (i == 1 && j == 1) continue;
                dp[i][j][0] = min(dp[i - 1][j][0], dp[i][j - 1][0]) + p[i][j].fi;
                dp[i][j][1] = min(dp[i - 1][j][1], dp[i][j - 1][1]) + p[i][j].se;
            }
        }
    /*
        haha;
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                printf("%lld%c", min(dp[i][j][0], dp[i][j][1]), j == n ? '
    ' : ' ');
    */
        LL ans = min(dp[n][n][0], dp[n][n][1]);
        if (flag && ans >= flag){
            ans = 1LL * flag;
            printf("%lld
    ", ans);
            int cnt = 0;
            for (int i = 2; i <= zero.fi; i++) printf("D"), cnt++;
            for (int i = 1; i < n; i++) printf("R"), cnt++;
            for (int i = zero.fi + 1; i<= n; i++) printf("D"), cnt++;
            cout << endl;
            return 0;
        }
        printf("%lld
    ", ans);
        dfs(n, n, dp[n][n][0] > dp[n][n][1]);
        for (int i = 0; i < v.size(); i++)
            printf("%c", v[i]);
        cout << endl;
        return 0;
    }
    
    /*
    4
    1 10 10 10
    1  0  1 10
    10 10 2 10
    1  10 1 1
    */
    View Code
  • 相关阅读:
    A Simple Problem About Truth Table
    Android Fragment完全解析,关于碎片你所需知道的一切
    Android系统中标准Intent的使用
    Android应用开发全程实录-你有多熟悉listView
    Android四大基本组件介绍及生命周期
    设计模式
    Java流(Stream)、文件(File)和IO
    Java网络编程详解
    Java 多线程
    深入理解Java虚拟机 精华总结(面试)
  • 原文地址:https://www.cnblogs.com/heimao5027/p/5987733.html
Copyright © 2011-2022 走看看