• 解题报告: CF2B


    题目链接:CF2B The least round way
    显然需要 (dp) 解决。
    第一个思路:用 (dp_{i}{j})代表第 (i) 行第 (j) 列最小的后缀 (0) 数,不幸的是,他被 hack 了。
    考虑 (10)的形成,贡献只来自于 (2)(5) 这个因数。
    我们容易想到最小化 (min{sum a_i,sum b_i})
    ps:(sum a_i) 代表路径中数含有因子 (2) 的数量,(sum b_i) 代表路径中数含有因子 (5) 的数量。
    于是我们就有了两个子任务,最小化 (sum a_i)(sum b_i),然后再取 (min)
    这就是两个简单 (dp) 了(我没骗你吧)。
    我们记 (dp1_{i,j}) 为到坐标为 ((i,j)) 的点最小的 (sum a_i)
    我们记 (dp2_{i,j}) 为到坐标为 ((i,j)) 的点最小的 (sum b_i)
    可以得到递推式:

    [dp1_{i,j}=min{dp1_{i-1,j},dp1_{i,j-1}}+a_{i,j} ]

    [dp2_{i,j}=min{dp2_{i-1,j},dp2_{i,j-1}}+b_{i,j} ]

    对于 (a_{i,j})(b_{i,j}) 是可以直接预处理出来的(每次判断是否整除),这个处理的期望复杂度应该是 (mathcal O(n^2))
    于是我们就能得到一个复杂度为 (mathcal O(n^2)) 的算法。
    但是还有个坑:矩阵中的数可能为零,这是 (2)(5) 也没有贡献。
    我们只需判断有没有答案为 (0) 的走法(乘积为 (0) 时答案为 (1)),如果不存在,只需找一条经过 (0) 的路线即可。
    废话不多说,上代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    using namespace std;
    
    #define read(x) scanf("%d",&x)
    #define readl(x) scanf("%lld",&x)
    #define ll long long 
    #define inf 2147483647
    
    int n;
    int x[1005][1005];
    int a[1005][1005],b[1005][1005],dp1[1005][1005],dp2[1005][1005];
    int sum1[1005][1005],sum2[1005][1005];
    int op1[1005][1005],op2[1005][1005];
    int ans[1000005],cnt=0;
    int flag=0,xx,yy; 
    
    inline int cal(ll n,int a)
    {
    	int ans=0;
    	while(n%a==0&&n!=0) ans++,n/=a;
    	return ans;
    }
    
    int main()
    {
    	read(n);
    	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) readl(x[i][j]),dp1[i][j]=inf,dp2[i][j]=inf;
    	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(x[i][j]==0) flag=1,xx=i,yy=j;
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=n;j++) a[i][j]=cal(x[i][j],2),b[i][j]=cal(x[i][j],5);
    	}
    	dp1[1][1]=a[1][1],sum1[1][1]=b[1][1];
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=n;j++)
    		{
    			if(i==n&&j==n) continue;
    			if(i<n)
    			{
    				if(dp1[i+1][j]>=dp1[i][j]+a[i+1][j]) 
    				{
    					dp1[i+1][j]=dp1[i][j]+a[i+1][j];
    					op1[i+1][j]=1;
    					sum1[i+1][j]=sum1[i][j]+b[i+1][j];
    				}
    			}
    			if(j<n)
    			{
    				if(dp1[i][j+1]>=dp1[i][j]+a[i][j+1])
    				{
    					dp1[i][j+1]=dp1[i][j]+a[i][j+1];
    					op1[i][j+1]=2;
    					sum1[i][j+1]=sum1[i][j]+b[i][j+1];
    				}
    			}
    		}
    	}
    	dp2[1][1]=b[1][1],sum2[1][1]=a[1][1];
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=n;j++)
    		{
    			if(i==n&&j==n) continue;
    			if(i<n)
    			{
    				if(dp2[i+1][j]>=dp2[i][j]+b[i+1][j]) 
    				{
    					dp2[i+1][j]=dp2[i][j]+b[i+1][j];
    					op2[i+1][j]=1;
    					sum2[i+1][j]=sum2[i][j]+a[i+1][j];
    				}
    			}
    			if(j<n)
    			{
    				if(dp2[i][j+1]>=dp2[i][j]+b[i][j+1]) 
    				{
    					dp2[i][j+1]=dp2[i][j]+b[i][j+1];
    					op2[i][j+1]=2;
    					sum2[i][j+1]=sum2[i][j]+b[i][j+1];
    				}
    			}
    		}
    	}
    	if(min(dp1[n][n],dp2[n][n])>=1&&flag)
    	{
    		printf("1
    ");
    		for(int i=2;i<=yy;i++) putchar('R');
    		for(int i=2;i<=n;i++) putchar('D');
    		for(int i=yy+1;i<=n;i++) putchar('R');
    	}
    	else if(dp1[n][n]<=dp2[n][n])
    	{
    		printf("%d
    ",min(dp1[n][n],sum1[n][n]));
    		int x=n,y=n;
    		while(x+y!=2)
    		{
    			if(op1[x][y]==1) ans[++cnt]=1,x-=1;
    			else ans[++cnt]=2,y-=1;
    		}
    		for(int i=cnt;i>=1;i--) 
    		{
    			if(ans[i]==1) printf("D");
    			else printf("R");
    		}
    	}
    	else 
    	{
    		printf("%d
    ",min(dp2[n][n],sum2[n][n]));
    		int x=n,y=n;
    		while(x+y!=2)
    		{
    			if(op2[x][y]==1) ans[++cnt]=1,x-=1;
    			else ans[++cnt]=2,y-=1;
    		}
    		for(int i=cnt;i>=1;i--) 
    		{
    			if(ans[i]==1) printf("D");
    			else printf("R");
    		}
    	}
    	putchar('
    ');
    	return 0;
    }
  • 相关阅读:
    C#使用SSDB管理增量日志并提供查询
    请假系统特例规则详细设计
    2014年国内最热门的.NET开源平台
    MQTT--入门
    转MQTT--Python进行发布、订阅测试
    Python修改文件权限
    Python Windows文件操作
    python random 学习
    Python---copy()、deepcopy()与赋值的区别
    使用Git Bash从Git上下载代码到本地以及上传代码到码云Git
  • 原文地址:https://www.cnblogs.com/tlx-blog/p/12706147.html
Copyright © 2020-2023  润新知