题目出处:http://codeforces.com/problemset/problem/2/B

题目描述

给你一个 \(n \times n\) 的二维数组,它包含的元素都是非负整数。你需要寻找一条满足如下条件的行走路线:

  • 这条路线的起始位置在二维数组的左上角;
  • 每一步你只可以从当前的位置往右或者往下走一格;
  • 这条路线的终止位置在二维数组的右下角。

此外,如果我们一路上把所有的数字相乘,结果应该是最不“圆”的。换句话说,这个乘积结尾的 \(0\) 应该尽可能地少。

输入格式

输入的第一行包含一个整数 \(n(2 \le n \le 1000)\) ,用于表示二维数组的大小。

接下来 \(n\) 行,每行包含 \(n\) 个元素用于表示这个二维数组(数据保证二维数组的每个元素都是非负整数并且不超过 \(10^9\) )。

输出格式

输出的第一行包含一个整数,用于表示最不圆路线的结尾 \(0\) 的个数。

输出的第二行用于表述路线(具体表述方式见样例输出,一个字符 'R' 表示向右走一格,一个字符 'D' 表示向下走一格)。

样例输入

3
1 2 3
4 5 6
7 8 9

样例输出

0
DDRR

题目分析

本题涉及算法:动态规划。

接下来我们来正式将解题思路:

我们设左上角坐标为 \((0,0)\) ,右下角坐标为 \((n-1,n-1)\) ,同时我们设:

  • \(a[i][j]\) :表示数组第 \(i\) 行第 \(j\) 列的元素;
  • \(num2[i][j]\) :表示 \(a[i][j]\) 最多能分解出的 \(2\) 的数量;
  • \(num5[i][j]\) :表示 \(a[i][j]\) 最多能分解出的 \(5\) 的数量;
  • \(f2[i][j]\) :表示从左上角 \((0,0)\) 走到 \((i,j)\) 的路线上所有数的乘积中包含的最少的 \(2\) 的数量;
  • \(f5[i][j]\) :表示从左上角 \((0,0)\) 走到 \((i,j)\) 的路线上所有数的乘积中包含的最少的 \(5\) 的数量。

然后我们可以根据 \(f2[n-1][n-1]\) 和 \(f5[n-1][n-1]\) 的大小来确定路线:

  • 如果 \(f2[n-1][n-1] \le f5[n-1][n-1]\) ,那我从 \((n-1,n-1)\) 到 \((0,0)\) 能够逆推出一条得到 \(f2[n-1][n-1]\) 的路线,我在一般情况下就是我们的答案;
  • 如果 \(f2[n-1][n-1] > f5[n-1][n-1]\) ,那我从 \((n-1,n-1)\) 到 \((0,0)\) 能够逆推出一条得到 \(f5[n-1][n-1]\) 的路线,我在一般情况下就是我们的答案。

注意,这里我说的是“一般情况”,那么什么是非一般情况呢,那就是存在一个元素为 \(0\) 的情况,那么这个时候又同时满足 \(min(f2[n-1][n-1] , f5[n-1][n-1]) > 1\) ,那么我们就不应该通过 \(f2\) 或者 \(f5\) 去逆推了,而是只需要找一条经过这个数值为 \(0\) 的位置的路线就可以了。

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010;
int n, a[maxn][maxn], num2[maxn][maxn], num5[maxn][maxn], f2[maxn][maxn], f5[maxn][maxn];
stack<char> res;
void output(int f[][maxn]) {
cout << f[n-1][n-1] << endl;
int r = n-1, c = n-1;
while (r && c) {
if (f[r-1][c] <= f[r][c-1]) { res.push('D'); r--; }
else { res.push('R'); c --; }
}
while (r) { res.push('D'); r --; }
while (c) { res.push('R'); c --; }
while (!res.empty()) {
putchar(res.top());
res.pop();
}
}
int main() {
cin >> n;
for (int i = 0; i < n; i ++)
for (int j = 0; j < n; j ++) {
cin >> a[i][j];
while (a[i][j] > 0 && a[i][j] % 2 == 0) {
a[i][j] /= 2;
num2[i][j] ++;
}
while (a[i][j] > 0 && a[i][j] % 5 == 0) {
a[i][j] /= 5;
num5[i][j] ++;
}
}
for (int i = 0; i < n; i ++)
for (int j = 0; j < n; j ++) {
if (i == 0 && j == 0) {
f2[i][j] = num2[i][j];
f5[i][j] = num5[i][j];
}
else if (i == 0) {
f2[i][j] = f2[i][j-1] + num2[i][j];
f5[i][j] = f5[i][j-1] + num5[i][j];
}
else if (j == 0) {
f2[i][j] = f2[i-1][j] + num2[i][j];
f5[i][j] = f5[i-1][j] + num5[i][j];
}
else {
f2[i][j] = min(f2[i-1][j], f2[i][j-1]) + num2[i][j];
f5[i][j] = min(f5[i-1][j], f5[i][j-1]) + num5[i][j];
}
}
int r0 = -1, c0 = -1;
for (int i = 0; i < n; i ++)
for (int j = 0; j < n; j ++)
if (a[i][j] == 0) {
r0 = i; c0 = j;
}
if (r0 != -1 && min(f2[n-1][n-1], f5[n-1][n-1]) > 1) { // 如果存在数值为0且f2,f5较小值>1
int r = 0, c = 0;
cout << 1 << endl;
while (c < c0) { putchar('R'); c ++; }
while (r < r0) { putchar('D'); r ++; }
while (c < n-1) { putchar('R'); c ++; }
while (r < n-1) { putchar('D'); r ++; }
}
else
output(f2[n-1][n-1] <= f5[n-1][n-1] ? f2 : f5);
return 0;
}

codeforces2B.The least round way 题解 动态规划/模拟的更多相关文章

  1. 【CodeForces】704 C. Black Widow 动态规划+模拟

    [题目]C. Black Widow [题意]给定一个表达式,形式为(...)^(...)^......^(...)=1(n个括号),括号中为1~2个值取或.有m个变量,给出表达式的值为xi或 !xi ...

  2. LibreOJ β Round #2 题解

    LibreOJ β Round #2 题解 模拟只会猜题意 题目: 给定一个长为 \(n\) 的序列,有 \(m\) 次询问,每次问所有长度大于 \(x\) 的区间的元素和的最大值. \(1 \leq ...

  3. Google kickstart 2022 Round A题解

    Speed Typing 题意概述 给出两个字符串I和P,问能否通过删除P中若干个字符得到I?如果能的话,需要删除字符的个数是多少? 数据规模 \[1≤|I|,|P|≤10^5 \] 双指针 设置两个 ...

  4. Codeforces Round #556 题解

    Codeforces Round #556 题解 Div.2 A Stock Arbitraging 傻逼题 Div.2 B Tiling Challenge 傻逼题 Div.1 A Prefix S ...

  5. Codeforces Beta Round #3 C. Tic-tac-toe 模拟题

    C. Tic-tac-toe 题目连接: http://www.codeforces.com/contest/3/problem/C Description Certainly, everyone i ...

  6. Codeforces Beta Round #1 B. Spreadsheets 模拟

    B. Spreadsheets 题目连接: http://www.codeforces.com/contest/1/problem/B Description In the popular sprea ...

  7. 洛谷 P3695 CYaRon!语 题解 【模拟】【字符串】

    大模拟好啊! 万一远古计算机让我写个解释器还真是得爆零了呢. 题目背景 「千歌です」(我是千歌).「曜です」(我是曜).「ルビィです」(我是露比).「3人合わせて.We are CYaRon! よろし ...

  8. Codeforces Round #569 题解

    Codeforces Round #569 题解 CF1179A Valeriy and Deque 有一个双端队列,每次取队首两个值,将较小值移动到队尾,较大值位置不变.多组询问求第\(m\)次操作 ...

  9. Codeforces Round #557 题解【更完了】

    Codeforces Round #557 题解 掉分快乐 CF1161A Hide and Seek Alice和Bob在玩捉♂迷♂藏,有\(n\)个格子,Bob会检查\(k\)次,第\(i\)次检 ...

随机推荐

  1. 【CODEVS】2618 核电站问题

    2618 核电站问题 时间限制: 1 s 空间限制: 32000 KB 题目等级 : 黄金 Gold 题解 查看运行结果 题目描述 Description 一个核电站有N个放核物质的坑,坑排列在一条直 ...

  2. Leetcode671.Second Minimum Node In a Binary Tree二叉树中的第二小结点

    给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 2 或 0.如果一个节点有两个子节点的话,那么这个节点的值不大于它的子节点的值. 给出这样的一个二叉树,你需要输出所有节点中 ...

  3. CI框架--浅谈前后台区分

    谈到CI框架,这是我第二个用到的框架,初步使用过后,眼前一亮.CI框架上手简单.模式明确.适合新手学习框架时入手. 下面给大家讲讲CI框架区分前后台文件的具体做法: 首先在application文件夹 ...

  4. etcd使用

    下载: https://github.com/etcd-io/etcd/releases/tag/v3.3.13 tar -zxvf   etcd-v3.3.13-linux-amd64.tar.gz ...

  5. oracle 索引监控

           索引对于在大量数据里检索出少量数据库的查询操作来说是高效的,可是对于DML操作来说.却是负面的:①其对于insert 操作的反面影响最大.该表的索引越多,更新的索引越多,insert 操 ...

  6. 利用ajax异步校验验证码(转)

    利用ajax异步校验验证码 示例结果如图所示 具体步骤如下: step1: jsp页面及js脚本 <%@page pageEncoding="utf-8" contentTy ...

  7. 计算机网络3.2&3.3(第二节介质&第三节多路复用)

    有限的传播介质 双绞线 双绞线电缆 双绞线总结 2 同轴电缆 粗细电缆的传输距离 现在基本都用双绞线和光线 同轴电缆用于居民小区和家庭使用 3 光纤 光纤中以光信号的形式进行传播 正如我们现在看到这样 ...

  8. Python数据分析与展示[第二周]

    matplotlib 有各种可视化的类构成 一般调用 matplotlib.pypolt 这个命令字库 相当于快捷方式 plt.plot(a) 只有一个一维列表 x轴充当列表索引 plt.ylabel ...

  9. CSS3--关于z-index不生效问题

    最近写CSS3和js结合,遇到了很多次z-index不生效的情况: 1.在用z-index的时候,该元素没有定位(static定位除外) 2.在有定位的情况下,该元素的z-index没有生效,是因为该 ...

  10. 解决Apache日志"internal dummy connection"方法

    最近查看服务器中apache日志,发现有大量的 OPTIONS * HTTP/1.0" 200 - "-" "Apache (internal dummy co ...