CCNU 周练2(2016年9月)

这份题故挂出来之后由于 vjudge 挂了等原因少有人做。但我决定还是出个题解。

A. Page - CF399A

简单的模拟,按照题目要求画出导航栏的样子

B. Fancy Number - CF118C

给出一个 n 位十进制数,更改一个数位的代价即是前后该位的差的绝对值。问最少花费多少代价可以让数字出现至少存在 k 个连续相同数位。输出最小代价和修改的结果,如果多个结果代价相同,输出结果字典序最小的。

假设目标强化成存在至少 k 个连续相同的 d (0 ≤ d ≤ 9)。若当前 d 数目大于等于 k,则花费代价是 0;否则枚举先枚举花费小的位,让这些位的数改变为 d,记录代价。注意安排改变的顺序使答案的字典序小。使用数据结构是 std::vector pos[10]pos[d]保存的是原来数中 d 的位置。

重复加强的问题,枚举 d,就可以解决这道问题。

C. Lucky Number 2 - CF145B

一个数位只有 4 和 7 的数,给出 4 的个数,7 的个数,子串 47 的个数,子串 74 的个数。问原数字最小是多少,如果不能找到一个数字满足条件,输出 -1。

此题切入点是 47 串的个数与 74 串的个数差的绝对值不能超过 1,这一点不难证明。故分这个值是 -1、0、1 三种情况讨论,注意一些细节即可通过该题。

D. 旅行comf - HYSBZ1050

无向图起讫点之间求出最大边和最小边的比值最小的路径,输出这个比值。

当确定了最小边,最大边就应该尽量小,但又需要使得 s,t 之间相连。故只要枚举最小边,从小到大加边,找到使得起讫点联通的第一条边即可维护答案。时间复杂度是 O(m2)

E. Array and Operations - CF498C

给出一个长 n 的正整数列,给出 m 对下标,每对下标和是偶数。定义一个操作是可以任意选一对下标,将对应的两个数除以他们的某个大于一的约数(如果没有这样的约数不能进行此操作)。每对下标可以选择任意次。问最多可以进行多少此操作。

奇数和偶数分离,则得到一个二分图。每次除的素数都是素数显然是最优的。对每个奇数 o,起点到 o 连接边权是 o 宿因自素因子个数的边;o 到与之配对的偶数连边权为两者公素因数的个数的边;对每个偶数 e,连系终点边权为 e 的素因数个数的边。起讫点之间的最大流即是答案。此题还可以使用二分图其他性质解决。

F. Wet Shark and Blocks - CF621E

给出一个数组,是 n 个数重复出现 d 次,总长 n × d,且每个数都是 1 到 9。先从每 n 个数中选择一个数组成一个长 d 的十进制数。问这个数模 x 结果是 k 的情况有多少种。答案对 109+7 取模。

f(l,r) 表示长 l,模 x 结果为 r 的方法数目。用 cnt[r] 记录每节的 n 个数中有多少是模 x 为 r 的。那么使用:

for (int p = 0; p < x; ++p) {
  for (int r = 0; r < 10; ++r) {
    int q = (10 * p + r) % x;
    o[q][p] = (o[q][p] + cnt[r]) % MOD;
  }
}

即可出理出 f 的转移矩阵,之后进行矩阵快速幂即可得到结果。

G. Pillars - CF474E

给 n 根柱子的高度,任选起点向后跳,之后某个柱子高度与当前高度相差 d 或者以上即可跳。问最多可以跳几次。

离散化高度,用 f(s) 表示结尾高度为 s 时跳的最大步数。考虑添加一个柱子,高度是 h,则能跳到当前柱子的状态有 f(0...sd) f(h+d...maxh) ,记这些的最大值是 u,则 f(h) 取之与 u+1 的较大值。对于 f 需要能查询区间的最大值以及修改单点元素,树状数组和线段树都是可以胜任的。

Posted by 张静之

你可能感兴趣的:(CCNU 周练2(2016年9月))