2022寒假测试8解析
2022年寒假第8次测试解析。
T1 「JOISC 2016 Day 2」女装大佬
原题为 JOISC 2016 Day2 T3 「トイレ」。
题面
题面
题目描述
题目译自 JOISC 2016 Day2 T3 「トイレ」
题面魔改原因:原题是男选手太多所以要借用女厕所 译者表示无法接受
IOI 的队服有两种,一种男装,一种是女装。然而很遗憾,所有参赛队伍中并没有女生,只有女装大佬。现在 IOI 设置了两个发放点,一个点只发放男装,另一个点只发放女装。
现在,所有队伍总共 $2N$ 个参赛队员,他们排成一列来领取队服,领取队服的规则如下:
- 当前队首是女装大佬,如果领取女装的地方是空的,那么他就会领取女装,否则如果领取男装的地方是空的,他会去领取男装;
- 当前队首是正常男生,如果领取男装的地方是空的,那么他会领取男装,否则如果女装位空着,他就发挥绅♂士精神,给身后的最前面的女装大佬让位,让他先领取女装。
已知任意一个人领取队服都需要一分钟的时间,现在你需要重排所有人的顺序,使他们在 $N$ 分钟内领完队服 。
定义一个人的 Dark 值为:在重排队伍之前在他后面,且重排队伍之后在他前面的人的数量。
你现在需要找出重排后整个队伍最大的 Dark 值至少为多少。
输入格式
第一行为一个数 $N$ ,为领完队服的时限,同时 $2N$ 代表着总领队服人数,需要注意的是,这不意味着正常男生和女装大佬刚好各占 $N$ 个;
第二行为一个数 $M$,指队伍共有 $M$ 种;
之后的 $M$ 行,第 $i$ 行包括一个字符串和一个数字,描述该队伍的组成,其中M
表示正常男生,F
表示女装大佬,之后的一个数字,表示该字符串连续出现了几次。所有字符串长度乘上出现次数的和等于 $2N$。
输出格式
一个数,表示重排后最大 Dark 值的最小值,如果在 $N$ 分钟内不能完成领取队服的任务,输出 $−1$。
思路
(这里的说法是基于原题“トイレ”的背景——撤硕分配来说的)
首先我们需要判断哪个序列是一个可行的方案。
我们虽然可以从头开始模拟,但是这样需要耗费的时间实在是太多了。
因此,我们考虑从最后一分钟倒推。
既然我们有两个撤硕,总共 $2N$ 个人,需要在 $N$ 分钟内解决问题,那么必须是每一分钟都有两个人在上厕所。
那么我们看一下最后一分钟。
如果最后一分钟在队列里面等待的是两个男生,那么他们已经可以商量谁去女厕所了。
所以我们可以猜想,男的必须尽量靠前。
我们尝试将每一个 F
当做 $-1$,M
当做 $1$,基于此统计其后缀和。
我们需要确保所有人加起来不大于0,即最多有 $N$ 个男生。
我们还需要确保每一段后缀和都不大于1。自己用手推算一下的话,那么我们可以轻易发现,一旦有后缀和超过1的情况的话,那么最后肯定有两个(或更多)男生需要决定谁进女厕所。
我们可以选择二分让队尾多少个男生去往队头,也可以统计整个序列中后缀和最大值之后再+1。
代码
100分代码:
1 |
|
一发36分的Java8代码:
Java8
1 | //import java.util.Arrays; |
T2 【常中20180812T3】 test
题面
题面
题目背景
Tom在学写动态树,但是做题时过了样例,提交RE。Tom抓住Jerry要他写个暴力来对拍。Jerry觉得这任务太简单了,就让你来完成一下。
题目描述
有一棵 $n$个节点的树,初始时根节点为1。现在要支持如下操作——
- 将某节点设置为根;
- 改变某节点权值;
- 询问以某节点为根的子树内节点权值之和;
- 询问以某两点为端点的链上的节点权值之和。
输入格式
第一行两个正整数 $n$ 和 $q$ ,表示树的节点数和操作个数。
接着 $n−1$ 行每行两个整数 $u$ 和 $v$ ,表示有连接 $u$ 和 $v$ 的一条边。
随后一行 $n$ 个正整数,表示每个点的初始权值。
之后 $q$ 行每行格式如下:
首先一个范围为 $[1,4]$ 的正整数,表示该操作类型。
对于1操作,之后一个正整数 $x$ ,表示将 $x$ 节点设置为根。
对于2操作,之后两个正整数 $x$ 和 $v$ ,表示将 $x$ 节点的权值改为 $v$ 。
对于3操作,之后一个正整数 $x$ ,表示询问以 $x$ 为根的子树内节点权值之和。
对于4操作,之后两个正整数 $x$ 和 $y$ ,表示询问以 $x$ 和 $y$ 为端点的链上的节点权值之和。
输出格式
对于每个操作3和操作4,输出一行一个整数表示询问的答案。
思路
根据题目所给出的要求,我们可以使用LCT做这道题。
但是LCT太难了我不会啊QwQ
所以我们考虑退而求其次,使用换根树剖来做。
实测可行。
换根操作只会影响作用于一个节点子树上的操作,比如子树加,子树求和等等。
巧了,这里就有一个。
那就有点头疼。
我们根据要需要操作的节点 $x$ 和现根节点 $rt$ 的关系来考虑分三种情况:
x==rt
这种情况明显很简单——就是整棵树。lca(x,rt)!=x
这样我们可以知道现在的根 $rt$ 没有在 $x$ 的子树里,此时 $x$ 的子树与根为1时的子树无异,可以直接操作。lca(x,rt)==x
这时候我们发现 $rt$ 在 $x$ 的子树里面。
此时,$x$ 的子树就会发生很大的改变。原先 $x$ 的子树包含 $rt$ 的那个儿子现在成为了 $x$ 的父亲,而其他儿子不变。原先为 $x$ 父亲的节点成为了 $x$ 的其中一个儿子,原先除其子树以外的节点都成为了其子树。
我们称这个子树包含 $rt$ 的儿子为 $v$ 。
现在 $x$ 的子树是 $[ 1 , id_v ) \cup ( id_v + sz_v - 1 , n ]$ 这两段连续的区间。
我们可以考虑对这两段区间分别操作,也可以选择对整棵树操作以后在减去中间的那一块er。
代码
100分代码:
1 |
|
re的Java8代码(求调):
Java8
1 | import java.util.Arrays; |
T3 【20180819省队班】 取数字
题面
题面
题目描述
给定 $n$ 个整数 $a_i$,你需要从中选取若干个数,使得它们的和是 $m$ 的倍数。问有多少种方案。有多个询问,每次询问一个的 $m$ 对应的答案。
输入格式
第一行两个正整数 $n$,$q$,分别表示整数的数量和询问的数量。
第二行 $n$ 个整数 $a_i$ 。
接下来 $q$ 行,每行表示一个 $m$。
输出格式
对于每个询问,输出一行答案 $\bmod{1e9+7}$。
思路
这道题是个背包计数的问题,背包的容量是模m循环的。
记f[i][j]
表示考虑了前 $i$个整数,当前余数是 $j$,有选和不选两种情况。那么对于一次询问 $q$,我们直接做的复杂度是 $O(nm)$,总复杂度 $O(nmq)$。这档暴力分应该拿到。
我们注意到m很小,而n很大,也就是说有很多重复的值,那么我们考虑设计一个下标为dp[m][m]
的DP方法,每次考虑一类数。
假设第 $i$ 种数有 k[i]
个,我们的转移是:
$$
dp[i][j]=\sum_{h=0}^{k[i]} C_{k[i]}^h dp[i-1][j - h \times a[i] \bmod m]
$$
注意到 $\sum k[i]=n$ ,以及dp数组的第二维最大只有m,因此我们可以每次 $O(k[i])$ 地预处理出组合数的系数,表示dp[i-1][j]
的贡献。写成伪代码就是:
1 | for h : [0, k[i]] |
然后我们再递推dp[i][j]
,把 $dp[i-1][j]\times c[k]\to dp[i][j+k\times i\bmod m]$ 即可。
总复杂度$O(q(n+m^3))$。
代码
100分代码:
1 |
|
re的Java8代码(求调):
Java8
1 | import java.util.Arrays; |