Codeforces Beta Round #2 B. The least round way

602 阅读1分钟

题目链接

思路

除了最终结果为0的情况,末尾出现的零只能来自2和5的乘积。可以通过动态规划求出到终点经过数包含2和5作为因数的次数分别是多少,两者中的最小值就是末尾0的数目。
考虑图中有0的情况,如果经过这个点那么最终结果必定只有一个0,因此对他单独处理,只有不走0得到的最优解为0的情况下才不从0上经过,否则就直接走0。
看了看网上题解,在打印答案时可以通过反向搜索来保证输出顺序正确,以及初始化的一个小细节。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
using namespace std;
const int N=1E3+10,INF=0x3f3f3f3f;
int n,dir,zero;
int f[N][N][2];
void dfs(int x,int y)
{
	if(x==1 && y==1)
		return;
	if(f[x-1][y][dir]>f[x][y-1][dir])
	{
		dfs(x,y-1);
		putchar('R');
	}
	else
	{
		dfs(x-1,y);
		putchar('D');
	}
}
int main()
{
	cin>>n;
	rep(i,2,n)
		f[i][0][0]=f[i][0][1]=f[0][i][0]=f[0][i][1]=INF;
	rep(i,1,n)
	{
		rep(j,1,n)
		{
			int k;
			scanf("%d",&k);
			if(k==0)
			{
				zero=i;
				continue;
			}
			while(k%2==0)
			{
				++f[i][j][0];
				k>>=1;
			}
			while(k%5==0)
			{
				++f[i][j][1];
				k/=5;
			}
			rep(p,0,1)
			{
				if(f[i-1][j][p]<f[i][j-1][p])
					f[i][j][p]+=f[i-1][j][p];
				else
					f[i][j][p]+=f[i][j-1][p];
			}
		}
	}
	dir=f[n][n][0]>f[n][n][1];
	if(min(f[n][n][0],f[n][n][1])>1 && zero)
	{
		cout<<1<<endl;
		rep(i,2,zero)
			putchar('D');
		rep(i,2,n)
			putchar('R');
		rep(i,zero+1,n)
			putchar('D');
		return 0;
	}
	cout<<min(f[n][n][0],f[n][n][1])<<endl;
	dfs(n,n);
}

参考博客