Codeforces Round 957 赛后总结

Codeforces Round 957 (Div. 3)icon-default.png?t=N7T8https://codeforces.com/contest/1992

总体情况

赛时通过 4 题,赛后通过 7 题。Rating 加了 534 分。

重点/有价值的题目:E、F、G。

A Only Pluses (Accepted *2)

题意:给你 3 个数 a,b,c,可以最多五次对其中一个数执行加一操作。问若干次操作后三个数的最大乘积。

赛时做法:分别在 [0,5] 区间范围内枚举增量 i,j,k,当 i+j+k=5 时计算 \max((a+i)(b+j)(c+k))。

正解:贪心,每次操作把当前最小的数加一(设此时 a\leq b\leq c,则把 a 增加一可以使答案增加 bc,同理增加 b,c 可以使答案分别增加 ac,ab。而 bc\geq ac\geq ab,故每次将最小的数加一,一定不比其他任何方案更差)。

分析&推广:设有 n 个待操作数,最多进行 m 次操作,则赛时做法为 O(m^n);正解为 O(m*n\log n),更优。

B Angry Monk (Accepted *1)

题意:给你一个长度为 k 的序列 a_1,a_2,\dots,a_k 且 \sum a_i=n。每次可以将 a_i 分解成 a_i-1,1 两个数,也可以将 a_i 与数列中已经存在的某个 1 合并成 a_i+1。问最少需要多少次操作可以将 a 序列变成一个数 n。

赛时做法/正解:根据数据范围可知复杂度为 O(n)。如果要合并 x,y 两个数(设 1<x\leq y)就需要先通过 x-1 次操作将 x 分解成 x 个 1,再通过 x 次操作将这些 1 合并到 y 上面,整个过程需要 2x-1 次操作。要解决原问题,就要把最接近于 n 的数(最大的数,设为 m)与其他所有数合并。答案为 2(n-m)-(k-1)。

C Gorilla and Permutation (Accepted *1)

题意:对于 1- n 的排列,给定 m,k,定义 g(i) 表示前 i 个数中所有 \leq m 的数之和,定义 f(i) 表示前 i 个数中所有 \geq k 的数之和。构造一个 1-n 的排列,最大化 \sum_{i=1}^n f(i)-\sum_{i-1}^n g(i) 的值,输出一种合法方案即可。

赛时做法/正解:要最大化这个式子的值,就要最大化 f(i) 并最小化 g(i)。最大化 f(i):因为 f(i) 表示的是符合要求的数之和,要让大数排在前面,尽可能多的被累加。最小化 g(i) 同理,让 1-m 从小到大排在整个序列的最后 m 位。最终的方案是前 n-m 个数从 n 到 n-m+1 降序排列,后 m 个数从 1 到 m 升序排列。

D Test of Love (Accepted *3)

题意:有一个长度为 n+1 的字符数组 a。对于 a_i,B 表示陆地,L 表示原木,C 表示鳄鱼,W 表示水。如果在陆地或原木上,可以往前跳 1-m 格;不能经过鳄鱼;如果在水里,可以往前游一格,但总共最多只能游 k 格。已知 a_0 和 a_{n+1} 都是 B,给定 a_1-a_n 的值,问能否从 a_0 到达 a_{n+1}。

赛时做法/搜索:复杂度 O(n)。直接根据题意广搜即可,记得用 vis 数组标记访问,否则会 MLE。

正解一/贪心:复杂度 O(n)。如果可以向前跳且可以跳到终点,就结束。如果可以向前跳但不能跳到终点,尽量跳到原木上因为不消耗游泳次数。如果不能跳到原木上,就在躲避鳄鱼的前提下尽可能跳多一点的格子(让游泳次数尽可能少)。

正解二/动规:复杂度 O(nm)。定义 dp_i 表示到达第 i 格,所剩的最多游泳距离/次数。初始值为 dp_0=k。状态转移:对于在 [\max(0,i-m),i-1] 区间范围内的任意 j,有 dp_i=\max(dp_j);如果 a_{i-1} 是原木,dp_i 还可以等于 dp_{i-1}-1;最终所有方案取最大值即可。

E Novice's Mistake (Accepted *1)

题意:定义 int_calc(int n, int a, int b) = a * n - bstring_calc(int n, int a, int b) 为整数 n 转化为字符串后重复 a 次,再截去最后 b 位得到的字符串所表示的数。给定整数 n,问有多少整数对 (a,b) 满足 a,b\leq 10^4 且 int_calc(n, a, b) == string_calc(n, a, b)

正解/暴力+构造:注意到 n*a-b 是严格小于 10^6 的,也就是说它最多有六位。先枚举答案的位数 len,取字符串 n+n+\dots 长度为 len 的前缀字符串 tar,并用 stoll 函数计算出这个字符串对应的整数值 itar。枚举 a 的值,可以推出此时 b 的值为 n*a-itar。再判断位数是否相符(a*|n|-b=len)即可。

F Valuable Cards (Accepted *1)

题意:定义一个区间是“坏的”,当且仅当从中找不到若干个数,它们的乘积等于 x。给定一个长度为 n 的数列 a_1,a_2,\dots,a_n 和一个整数 x(保证 a_i\neq x)。问该数列最少能被分成多少段,使得每一段都是坏的。

正解/贪心:为了让区间数量最小,每一个区间都贪心地尽可能多地取数,直到不能再取为止。维护一个集合 S 包含为了让当前区间符合要求,不希望加入的所有数。尝试加入 a_i 时,枚举 y\in S,如果 y=a_i 则新开一个区间;如果 y\equiv0\pmod {a_i} 则把 y\div a_i 加入集合(因为 y 是不想见到的数,此时有了 a_i,数 y\div a_i 也就不能出现了。如果出现,将其与 a_i 相乘,就出现了不想见到的 y)。按照这种方法贪心地扫描,就可以得出答案。

G Ultra-Meow

题意:对于集合 S 和整数 k,定义 f(S,k) 表示集合中未出现的正整数从小到大排列后的第 k 个。给定整数 n,求集合 K=\{x\mid x\in \mathbb{Z},1\leq x\leq n\} 的所有不同子集 b 的 f(b,|b|+1) 之和,再模 10^9+7 的结果。

赛时思路/正解/组合数学:题目提示 O(n^2)。枚举子集大小 sz\ (0\leq sz\leq n),sz=0 是空集。然后枚举 f 函数值 k,计算有多少个大小为 sz 的子集,满足 f 函数值为 k。首先 k 一定不能被选进集合里。在 1\sim k-1 的所有整数中,需要有恰好 sz 个整数不被选择,来保证 f 函数值为 k。但又考虑到 n 的限制,这部分的方案总数可以用组合数表示为 C(\min(n,k-1),k-1-sz)。设已经选择的数的个数 k-1-sz=a,那么还需要考虑大于 k 的数的选择方案数:共选择 sz-a 个数,从 \max(0,n-k) 个数中选择。最终把两个组合数相乘,再乘以 f 函数值 k,最终累加答案即可。

  • 15
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值