既然NOIp2018有原题,那么CSP-S2019之前做做原题是有帮助的
Day1 T1
Solution
根据人类智慧可以得知,答案显然为$(x + m \times 10^k) \mod n$
然后根据模运算对乘法封闭的性质,可以得到$(x \mod n + m \mod n + 10^k \mod n) \mod n$,于是快速幂即可.
Code
1 | /* Headers */ |
Day1 T2
Solution
这题和T1难度差距有点大啊……….
题意让我们最小化这个式子:
$$\sum_{i=1}^n (a_i - b_i) ^2$$
显然$a_i,b_i$均为正整数,那么只需要最小化$a_i - b_i$即可.
也就是说,两个序列的第$k$大值所处的位置必须相同($1 \leq k \leq n$)
考虑对两个序列进行离散化,那么问题转化为离散化后的$B$序列如何通过最少的交换次数变成$A$序列.
设$bet_{a_i} = b_i$,即以$A$序列为关键字对$B$序列排序.
那么当两序列相等时,满足$bet_{a_i} = a_i$,即$bet_i = i$
那么问题转化为交换几次能使的$bet$数组满足升序排列,树状数组求逆序对即可.
Code
1 | /* Headers */ |
Day1 T3
Solution
首先看完题我们就能想到Floyd最长路的算法,时间复杂度$O(n^3)$
我们设一个$w$数组来表示最大载重,状态转移方程式也不难推出,为:
$$w_{i,j} = max(w_{i,j},min(w_{i,k},w_{k,j}))$$
开始考虑优化:
我们可以发现,很多权值较小的边绝对不在我们的考虑范围内,所以我们可以将它们去掉。
因为我们要求走过的边权尽可能大,所以我们可以构建一棵最大生成树。
现在有了这样一棵最大生成树,我们就要考虑如何求出两个节点之间的最小边权的最大值。
因为树上的两个节点之间只有唯一的一条路径,所以我们就可以求出这两个点的最近公共祖先(这里我们用树上倍增实现)
此题代码实现难度和思考难度均较大(对于Herself32这种菜鸡来说),是一道不错的图论进阶题目。
Code
半年前的毒瘤码风请见谅/kel
1 | /* Headers */ |
Day2 T1
Solution
考虑贪心.
首先把第一位读入进来,存入答案.
然后枚举整个数列,每次用下一个数与当前数比较:
- 若下一位大于这一位,就说明已经放的积木不够,答案加上当前数与上一个数的差
- 若下一位小于或等于这一位,说明已经放的积木够了,不需要更新答案.
Code
1 | /* Headers */ |
Day2 T2
Solution
首先,题目要求的数列是在给定数列的基础上,去掉一些数之后,满足每一个数都是相邻三个数中最大的或最小的.
那么我们考虑dp
设$dp_{i,0/1}$表示前$i$个数选择满足条件$1/2$的最大长度.
那么显然目标状态是$\max(dp_{n,0},dp_{n,1})$
考虑如何转移, 这里我们就要考虑当前的数是选择满足条件$1$还是条件$2$了.
我们还是拿第$2 \dots n$个数和前面那个数比较:
若下一位大于这一位
- 如果让此元素满足条件$1$并选它,那么答案应为令这一位元素满足条件$2$时的最大长度$+1$; 如果不选, 那么答案应直接继承上一位的答案.
- 如果让此元素满足条件$2$,就只能继承前一个点的答案.
若下一位小于这一位
和上面的推导过程类似,对称考虑即可.
若下一位等于这一位
因为这两个元素完全等价,那么直接继承前一个点的答案即可.
Code
1 | /* Headers */ |
Day2 T3
博主太菜了,这题还没补,暂时先鸽着吧….