码迷,mamicode.com
首页 > 其他好文 > 详细

解题报告: CF2B

时间:2020-04-15 16:33:01      阅读:90      评论:0      收藏:0      [点我收藏+]

标签:矩阵   路径   else   fine   div   strong   https   cst   因子   

题目链接: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\n");
		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\n",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\n",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(‘\n‘);
	return 0;
}

解题报告: CF2B

标签:矩阵   路径   else   fine   div   strong   https   cst   因子   

原文地址:https://www.cnblogs.com/tlx-blog/p/12706147.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!