首页 > 代码库 > 10day2

10day2

最多因子数

搜索

【问题描述】

数学家们喜欢各种类型的有奇怪特性的数。例如,他们认为 945 是一个有趣的数,因为它是第一个所有约数之和大于本身的奇数。

为了帮助他们寻找有趣的数,你将写一个程序扫描一定范围内的数,并确定在此范围内约数个数最多的那个数。不幸的是,这个数和给定的范围的都比较大,用简单的方法寻找可能需要较多的运行时间。所以请确定你的算法能在几秒内完成最大范围内的扫描。

【输入】

只有一行,给出扫描的范围,由下界 L 和上界 U 确定。满足 2≤L≤U≤1000000000。

【输出】

对于给定的范围,输出该范围内约数个数 D 最多的数 P。若有多个,则输出最小的那个。请输出"Between L and U,P has a maximum of D divisors.",其中 L,U,P 和 D 的含义同前面所述。

【输入样例】

1000 2000

【输出样例】

Between 1000 and 2000, 1680 has a maximum of 40 divisors.

【解题过程】

一开始毫无思路。

后来想到乱搞算法:枚举每个质因数的指数,最后凑成一个在 [L, R] 范围内的数。每次可以根据范围来确定质因子的指数范围,而每次增加一个质因子或者增加质因子的指数的时候搜索的范围就会变小,从而达到剪枝的目的。

我一开始以为这种乱搞算法是没问题的,但是后来 LZW 大神提出,如果 L=R=一个很大的质数,乱搞算法肯定跪。想了一下发现他说的好有道理,我竟无言以对。

由于是乱搞,我素数表只开到了几十,最后也骗到了几分。

后来发现其实标程也是乱搞算法,只不过素数表开得比较大,然后加了一个剪枝:如果在现在的范围 [L‘, R‘] 内没有某个质数的倍数,就不用搜这个质数了。这样还是无法处理上面所述的特殊情况。

所以这道题的正确做法不是搜索而是乱搞。

?

改造二叉树

动态规划

【问题描述】

在计算机科学中,二叉树是每个结点最多有两个子结点的有序树。通常子结点被称作"左孩子"和"右孩子"。二叉树常被用作二叉搜索树和二叉堆。

我们再讨论二叉搜索树。什么是二叉搜索树呢?二叉搜索树首先是一棵二叉树。设 key[p]表示节点 p 上的数值。对于其中的每个节点 p,若其存在左孩子 lch,则 key[p]>key[lch];若其存在右孩子 rch,则 key[p]<key[rch]。注意,应该是所有的左子树中的 key 小于当前 key,所有右子树中的 key 大于当前 key。

对于每个结点,无论如何改变其数值,费用总等于 1。现给定一棵二叉树,可以任意修改结点的数值。要求用最小的费用将其变成一棵二叉搜索树。

【输入】

输入文件包括两行,第一行是一个整数 n,表示二叉树的节点数。第二行包含 n 个整数,用空格分隔,第 i 个整数 ai 是第 i 个节点的原始数值。此后 n-1 行每行两个整数,第 i 行描述编号为 i-1的节点的父亲编号以及父子关系(0 表示为左孩子,1 表示为右孩子)。编号为 1 的节点一定是二叉树的根。

【输出】

输出文件包括一行,这一行只包含一个整数,也就是最小的费用值。输入数据保证这个值小于 2^31。

【输入样例】

3

2 2 2

1 0

1 1

【输出样例】

2

【数据规模】

对于 50%的数据,保证有 n<=100 且 0<=ai<=200;

对于 100%的数据,保证有 n<=100000。

【解题过程】

由于 BST 的中序遍历是个有序序列,所以我们很容易想到对给定的树进行中序遍历,然后问题就转化为将一个序列变为一个有序序列最少需要多少次修改。

很明显的 LIS。但是注意,修改之后的数字依然是整数(就是因为不知道这一点,然后跪了。),也就是说,有些情况下并不能直接求 LIS,比如一个中序遍历序列 2 1 3,如果可以修改成实数,那么显然最少修改次数=总数-LIS 长度,但是这里 1 并不能改成区间 (2, 3) 之间的实数,所以直接求 LIS 是会跪的。

再稍作分析,我们要求的最终序列应该满足的条件是对于任意的 i<j,都有 Aj-Ai>=j-i。还是以 2 1 3 为例,a[1]=2 与 a[3]=3 并不满足 3-2>=3-1+1,所以必然要修改其中的一个值。

对于上面的式子移项后可得 Aj-j>=Ai-i,那么我们只要把原序列中每个数 Ax 减去一个 x 然后再求最长非降子序列就是最后答案。

?

冒险岛

二分答案+动态规划

【问题描述】

我们的主人公 F1(没什么名字好取,为了简单,暂且这样)来到了一块神秘的地方——冒险岛。这是一个充满荆棘的地方,随时都可能有生命危险。F1 也深知这一点,他做好了充分的准备,他已经通过高空扫描技术对冒险岛进行了分析:

冒险岛是由 N*M 个单位方格组成,即 N 行 M 列的网格。格子有两种形式:沙漠与圣水湖。每一个沙漠都有一个摧毁值 D,当 F1 走到一个摧毁值为 D 的沙漠时,他的生命值将减少 D。每一个圣水湖都有一个容量 C,当 F1 走到一个容量为 C 的圣水湖时,它将得到 C 单位圣水。

主人公 F1 可以向下(行数增加)向右(列数增加)的移动,它必须从(1,1)走到(n,m)(第 n行 m 列,下同),中间不能走出这个岛。由于某种不为人知的力的作用(外星人?宇宙引力?或是四维空间中的"物质"?谁知道!),使得从(1,1)到(n,m)一定会经过沙漠。你不必担心 F1 的生命,也许他的生命值有无穷大,也许他凭着坚强的意志可以在生命值为负数的情况下移动——他一定能走出这个岛,在最后走出(n,m)时,他需要用他得到的所有圣水去弥补他失去的生命值,你只需关心他的"精神面貌值":得到的圣水与失去的生命值的比值。你需要使"精神面貌值"最大。

【输入】

第一行有两个整数 N,M(1<=N,M<=300),接下来 N 行,每一行有 M 个整数,第 i 行 j 个整数Pi,j(-1000000<=Pi,j<=1000000)描述格子(i,j)。如果小于 0,则表示摧毁值为|Pi,j|的沙漠;否则,表示容量为 Pi,j 的圣水湖。

【输出】

仅一个数,表示最大"精神面貌值",精确到小数点后 4 位。

【输入样例】

3 3

100 -20 -30

-100 -100 -100

-100 100 -100

【输出样例】

0.9091

【解题过程】

先讲自己做这道题时候的神思路:题目要求正的值与负的值的绝对值之比最大,就是求正的值加上负的值最大,就是求和最大的路径。很明显到第二个分句就已经错了,但是这样的乱搞算法也是可以骗到一半分数的。

正解是二分答案,用动态规划判定可行性。设正数和为 y,负数和为 x,则对于最终答案 ans 必然有 ans>=y/(-x),我们二分求出 ans 的最小值就是 y/(-x) 的最大值。对于上式,移项得 ans*x+y <= 0,那么对于二分出来的一个 ans 值,该式恒成立,所以用动规求出 ans*x+y 的最大值,判断是否满足条件即可。

10day2