Codeforces Beta Round #2 B

纪念下如此2B的题号。。。


DP啊,神啊,我看见DP俩字就颤 = =

第一反应是把每个数都分解为几个2几个5,以前ZOJ有道水题是计算多少个数乘积后有几个零,就是那种做法。

然后想着DP下最小的2或者5,想着不对,因为前面的2或者5的选择会影响后面,结果纠结了。

CFY说了个做法,扫两遍,单独计算2,5,然后目标点取最小的那个值即可。。。大悟。。T T 。。

找路径的话,就相当于从目标点往回找啦,或者你计算2,5的时候顺带记录下路径也可以。


关于0的处理,我是把0当做1个2, 1个5处理了,如果这个结果大于1,那么就输出1哈,因为有0的话,无论乘多少都是0。


改变代码风格了,发现木有哈~向C++靠拢。。


#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <climits>
#include <cstring>
#include <string>
#include <algorithm>
#define MID(x,y) ( ( x + y ) >> 1 )
#define L(x) ( x << 1 )
#define R(x) ( x << 1 | 1 )
#define FOR(i,s,t) for(int i=(s); i<(t); i++)
#define BUG puts("here!!!")
#define STOP system("pause")
#define file_r(x) freopen(x, "r", stdin)
#define file_w(x) freopen(x, "w", stdout)

using namespace std;

const int MAX = 1010;
class NODE{
	public:
		int num[2];
		void add(int n2, int n5){
			this->num[0] = n2;
			this->num[1] = n5;
		}
		void init(int v){
			if( v == 0 )
				add(1, 1);
			else
				factor(v);
		}
		int ff(int v, int base){
			int ans = 0;
			while( v % base == 0 && v ){
				ans++;
				v /= base;
			}
			return ans;
		}
		void factor(int v){
			add(ff(v, 2), ff(v, 5));	
		}
};
NODE 	node[MAX][MAX];
int 	a2[MAX][MAX];
int 	a5[MAX][MAX];
void process(int n, int a[][MAX], int id){
	a[0][0] = node[0][0].num[id];
	FOR(i, 1, n)
		a[i][0] = a[i-1][0] + node[i][0].num[id];
	FOR(i, 1, n)
		a[0][i] = a[0][i-1] + node[0][i].num[id];
	FOR(i, 1, n)
		FOR(k, 1, n){
			a[i][k] = min(a[i-1][k], a[i][k-1]) + node[i][k].num[id];
		}
}
int dp(int n){
	memset(a2, 0, sizeof(a2));
	memset(a5, 0, sizeof(a5));
	process(n, a2, 0);
	process(n, a5, 1);
	return min(a2[n-1][n-1], a5[n-1][n-1]);
}
string road(int n, int a[][MAX], int val, int id){
	string out;
	int x = n-1, y = n-1;
	while( x != 0 || y != 0 ){
		if( x != 0 && a[x][y] == a[x-1][y] + node[x][y].num[id] ){
			x--;
			out += 'D';
		} else {
			if( y != 0 && a[x][y] == a[x][y-1] + node[x][y].num[id] ){
				y--;
				out += 'R';
			}
		}
	}
	string ans;
	for(int i=out.length()-1; i>=0; i--){
		ans += out[i];
	}
	return ans;
}

int main()
{
	int n, value;
	bool zero = false;
	int x, y;
	
	scanf("%d", &n);
	
	FOR(i, 0, n)
		FOR(k, 0, n){
			scanf("%d", &value);
			if( !value ){
				zero = true;
				x = i;
				y = k;
			}
			node[i][k].init(value);
		}
	
	int ans = dp(n);
	
	if( zero && ans >= 1 ){
		puts("1");
		FOR(i, 0, x)
			putchar('D');
		FOR(i, 0, y)
			putchar('R');
		FOR(i, x+1, n)
			putchar('D');
		FOR(i, y+1, n)
			putchar('R');
	} else {
		string out;
		if( ans == a2[n-1][n-1] )
			out = road(n, a2, ans, 0);
		else
			out = road(n, a5, ans, 1);
		printf("%d\n%s\n", ans, out.c_str());
	}
		
return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值