Codeforces Beta Round #2_B. The least round way(DP)

来源:互联网 发布:淘宝网大童店铺 编辑:程序博客网 时间:2024/06/04 00:23

题目传送门:http://codeforces.com/contest/2/problem/B


题型:动态规划、数论


题意:

      给出n*n的矩阵,从左上角走到右下角,只能向右走或者向下走,将路线上的值全部乘起来,问结果末尾0最少的路线。


分析:

      乘积的末尾0,取决于这些数的质因子中的2和5的对数,即决定与最少的2的个数或者是最少的5的个数。若对矩阵中的每个元素进行质因子分解,复杂度为O(n^2*sqrt(n))过大。由于只要2的个数和5的个数,那么只要对每个元素不断除2或者除5即可,复杂度为O(n^2*log(n))可以接受。

      采用DP进行路径的寻找,找出含2最少的路径和含5最少的路径,状态转移方程为:

                                           dp(i,j) = min(dp(i-1,j),dp(i,j-1)) + num(i,j);

      可以证明末尾0最少的路径是这两条路径中的一条,证明如下:

      反证法:假设有一条路径比这两条更优。

                   所以这条路径的2和5的对数最少,所以相比与其他路径,该路径上必然2最少或者5最少。

                   然而根据题设,

                   这条路径含2的个数和含5的个数都不是最少的。

                   矛盾。

                   所以2最少的路或者5最少的路最优。     得证。

        由于2最少的路径上的末尾0等于2的个数,5最少的路径上的末尾0等于5的个数,所以

                                         ANS = min(dp2(n,n),dp5(n,n));

        路径只需逆退即可。

        需要注意的是,如果矩阵元素中有0且ANS>1,那么结果为1,路径就是经过该元素所在点的任意路径。


代码:

#include<iostream>#include<cmath>#include<cstring>#include<cstdio>#define INF 0x3f3f3f3fusing namespace std;int n;int num2[1010][1010];int num5[1010][1010];int dp2[1010][1010];int dp5[1010][1010];char str[1234];int _x,_y;void init(){memset(num2,0,sizeof(num2));memset(num5,0,sizeof(num5));for(int i=0;i<=n;i++){dp2[i][0] = dp2[0][i] = 0;dp5[i][0] = dp5[0][i] = 0;}}void FindRoute2(){for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(i==1 && j==1){dp2[i][j] = num2[i][j];continue;}if(i==1){dp2[i][j] = dp2[i][j-1] + num2[i][j];continue;}if(j==1){dp2[i][j] = dp2[i-1][j] + num2[i][j];continue;}dp2[i][j] = min(dp2[i-1][j],dp2[i][j-1]) + num2[i][j];}}}void FindRoute5(){for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(i==1 && j==1){dp5[i][j] = num5[i][j];continue;}if(i==1){dp5[i][j] = dp5[i][j-1] + num5[i][j];continue;}if(j==1){dp5[i][j] = dp5[i-1][j] + num5[i][j];continue;}dp5[i][j] = min(dp5[i-1][j],dp5[i][j-1]) + num5[i][j];continue;}}}void Ask2(){int pre = 0;int i=n,j=n;while(i!=1 || j!=1){if(dp2[i][j-1]<dp2[i-1][j]){str[pre] = 'R';j--;}else{str[pre] = 'D';i--;}pre++;}for(int i=pre-1;i>=0;i--){printf("%c",str[i]);}puts("");}void Ask5(){int pre = 0;int i=n,j=n;while(i!=1 || j!=1){if(dp5[i][j-1]<dp5[i-1][j]){str[pre] = 'R';j--;}else{str[pre] = 'D';i--;}pre++;}for(int i=pre-1;i>=0;i--){printf("%c",str[i]);}puts("");}void Special(int xx,int yy){for(int i=2;i<=xx;i++){printf("D");}for(int i=2;i<=n;i++){printf("R");}for(int i=xx+1;i<=n;i++){printf("D");}puts("");}int main(){while(~scanf("%d",&n)){bool ts = false;init();int a,tmp;for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){scanf("%d",&a);if(a==0){_x = i;_y = j;ts = true;}tmp = a;while(tmp%2==0&&tmp>0){num2[i][j]++;tmp/=2;}tmp = a;while(tmp%5==0&&tmp>0){num5[i][j]++;tmp/=5;}}}FindRoute2();FindRoute5();int ans = min(dp2[n][n],dp5[n][n]);if(ts && ans>1){puts("1");Special(_x,_y);continue;}for(int i=0;i<=n;i++){dp2[i][0] = dp2[0][i] = INF;dp5[i][0] = dp5[0][i] = INF;}printf("%d\n",ans);if(dp2[n][n]<dp5[n][n]) Ask2();else Ask5();}return 0;}


0 0