Codeforces Beta Round #2 B. The least round way DP + 数论

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

题意: 

给定n*n的一个数字矩阵,求从左上角(1,1)走到右下角(n,n)将每个数字相乘,使得乘机中包含的0最少。要求只能往下走或者往右走。

思路:

状态转移方程很好看,关键是怎么保证所得乘积所含0个数最少。想一下如何才能使乘积中出现0呢?只有质因子2*5才能出现0,其余的质因子相乘不会出现。所以我们只要保证使得2与5的个数凑出来的10最少即可,即2与5的个数最少即可 我们肯定得到一条路线使得ans = min(2num,5num); ans的值在所有路线里是最小的。即得到了所得答案。

开始我同时枚举的路线上的2与5的个数,样例能过但是wa,其实这样写转移方程不对的。我们是要的是min(2num,5num),我们怎样保证2最少的同时保证5最少。。不好弄。

后来看了一下解题报告,我们分2与5讨论,一条路线保证2最少 第二条路线保证5最少  那么第一条的5num肯定大于第二条路线5num  第二条的2num肯定大于第一条的2num

这样我们只要去min(ans1,ans2)即可。因为再走别的路线肯定会出现大于第一条路线的2num大于第二条路线5num。还有一个trick就死如果矩阵中出现0这样我们只要保证路过0就可以得到1的值,结果就为min(ans1,ans2,1)了。

才开始自己写的在处理1的时候,原点(1,1)我都给输出了,二逼啊。。。导致错了好多次。。。。

View Code
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b)

#define ll long long
#define inf 0x7f7f7f7f
#define MOD 1073741824
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100007
#define M 150
#define N 1007
using namespace std;
//freopen("data.in","r",stdin);

struct point{
    int x,y;
}pre[2][N][N];//记录父亲节点

int dp[2][N][N];//0表示2的路径,1表示5的路径
int zx,zy;
int mat[2][N][N];
char path[4*N];//记录路径
int n;

int solve(int mk){
    int i,j;
    pre[mk][1][1].x = pre[mk][1][1].y = -1;
    dp[mk][1][1] = mat[mk][1][1];
    for (i = 1; i <= n; ++i){
        for (j = 1; j <= n; ++j){
            if (i == 1 && j == 1) continue;
            if (i == 1){
                dp[mk][i][j] = dp[mk][i][j - 1] + mat[mk][i][j];
                pre[mk][i][j].x = i;
                pre[mk][i][j].y = j - 1;
            }
            else if (j == 1){
                dp[mk][i][j] = dp[mk][i - 1][j] + mat[mk][i][j];
                pre[mk][i][j].x = i - 1;
                pre[mk][i][j].y = j;
            }
            else{
                int tp1 = dp[mk][i - 1][j];
                int tp2 = dp[mk][i][j - 1];
                if (tp1 < tp2){
                    dp[mk][i][j] = dp[mk][i - 1][j] + mat[mk][i][j];
                    pre[mk][i][j].x = i - 1;
                    pre[mk][i][j].y = j;
                }
                else{
                    dp[mk][i][j] = dp[mk][i][j - 1] + mat[mk][i][j];
                    pre[mk][i][j].x = i;
                    pre[mk][i][j].y = j - 1;
                }
            }
        }
    }
    return dp[mk][n][n];
}
int main(){
   // freopen("data.in","r",stdin);
    int i,j;
    int x;
    bool flag = false;
    scanf("%d",&n);
    for (i = 1; i <= n; ++i){
        for (j = 1; j <= n; ++j){
            scanf("%d",&x);
            if (x == 0){//记录0的位置
                zx = i;
                zy = j;
                flag = true;
                continue;
            }
            mat[0][i][j] = mat[1][i][j] = 0;
            //枚举2,5质因子的个数
            int tmp = x;
            while (tmp %2 == 0){
                mat[0][i][j]++;
                tmp /= 2;
            }
            tmp = x;
            while (tmp % 5 == 0){
                mat[1][i][j]++;
                tmp /= 5;
            }
        }
    }
    //puts("*********");
    int ans1 = solve(0);
    int ans2 = solve(1);
    int ans,mk;
    if (ans1 < ans2){
        ans = ans1;
        mk = 0;
    }
    else{
        ans = ans2;
        mk = 1;
    }
    //0的特殊处理
    if (flag && ans > 1){
        printf("1\n");
        //注意这里从2开始,我二逼的从1开始了,wa了无数次啊。。伤不起啊
        for (i = 2; i <= zy; ++i) printf("R");
        for (i = 2; i <= zx; ++i) printf("D");
        for (i = zy + 1; i <= n; ++i) printf("R");
        for (i = zx + 1; i <= n; ++i) printf("D");
    }
    else{
        printf("%d\n",ans);
        int len = 0;
        int dx = n, dy = n;
        int px = pre[mk][dx][dy].x ,py = pre[mk][dx][dy].y;
        CL(path,0);
        while (px != -1 && py != -1){
            if (px + 1 == dx){
                path[len++] = 'D';
            }
            else if (py + 1 == dy){
                path[len++] = 'R';
            }
            dx = px; dy = py;
            px = pre[mk][dx][dy].x;
            py = pre[mk][dx][dy].y;
           // puts(">>>>>>");
        }
        for (i = len - 1; i >= 0; --i)
        printf("%c",path[i]);
        printf("\n");
    }
    return 0;
}

 

再贴一下处理输出的函数节约内存的代码:

View Code
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b)

#define ll long long
#define inf 0x7f7f7f7f
#define MOD 1073741824
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100007
#define M 150
#define N 1007
using namespace std;
//freopen("data.in","r",stdin);

int g[2][N][N];
int dp[2][N][N];
int zx,zy;
int mat[2][N][N];
char path[4*N];
int n;

int solve(int mk){
    int i,j;
    g[mk][1][1] = 0;
    dp[mk][1][1] = mat[mk][1][1];
    for (i = 1; i <= n; ++i){
        for (j = 1; j <= n; ++j){
            if (i == 1 && j == 1) continue;
            if (i == 1){
                dp[mk][i][j] = dp[mk][i][j - 1] + mat[mk][i][j];
                g[mk][i][j] = 1;
            }
            else if (j == 1){
                dp[mk][i][j] = dp[mk][i - 1][j] + mat[mk][i][j];
                g[mk][i][j] = 0;
            }
            else{
                int tp1 = dp[mk][i - 1][j];
                int tp2 = dp[mk][i][j - 1];
                if (tp1 < tp2){
                    dp[mk][i][j] = dp[mk][i - 1][j] + mat[mk][i][j];
                    g[mk][i][j] = 0;
                }
                else{
                    dp[mk][i][j] = dp[mk][i][j - 1] + mat[mk][i][j];
                    g[mk][i][j] = 1;
                }
            }
        }
    }
    return dp[mk][n][n];
}
void Path(int mk,int x,int y){
    if (x == 1 && y == 1) return ;
    else if (g[mk][x][y] == 0){
        Path(mk,x - 1,y);
        printf("D");
    }
    else{
        Path(mk,x,y - 1);
        printf("R");
    }
}
int main(){
    //freopen("din.txt","r",stdin);
    int i,j;
    int x;
    bool flag = false;
    scanf("%d",&n);
    for (i = 1; i <= n; ++i){
        for (j = 1; j <= n; ++j){
            mat[0][i][j] = mat[1][i][j] = 0;
            scanf("%d",&x);
            if (x == 0){
                zx = i;
                zy = j;
                flag = true;
                continue;
            }
            int tmp = x;
            while (tmp % 2 == 0){
                mat[0][i][j]++;
                tmp /= 2;
            }
            tmp = x;
            while (tmp % 5 == 0){
                mat[1][i][j]++;
                tmp /= 5;
            }
        }
    }
    int ans1 = solve(0);
    int ans2 = solve(1);
    int ans,mk;
    if (ans1 < ans2){
        ans = ans1;
        mk = 0;
    }
    else{
        ans = ans2;
        mk = 1;
    }
    if (flag && ans > 1){
        printf("1\n");
        for (i = 2; i <= zx; ++i) printf("D");
        for (i = 2; i <= n; ++i) printf("R");
        for (i = zx + 1; i <= n; ++i) printf("D");
        printf("\n");
    }
    else{
        printf("%d\n",ans);
        Path(mk,n,n);
        printf("\n");
    }
    return 0;
}

 

posted @ 2012-10-27 23:31  E_star  阅读(344)  评论(0编辑  收藏  举报