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;

}

 

你可能感兴趣的:(codeforces)