IOI2020国家集训队作业 Part 2
CF627E Orchestra
CF639E Bear and Paradox
CF639F Bear and Chemistry
对原图边双缩点,建虚树,将边加入后再求边双。
CF666D Chain Reaction
CF666E Forensic Examination
建广义 \(\text{SAM}\) ,在 \(\text{parent}\) 树上线段树合并,查询区间最大值即可。
CF671D Roads in Yusland
可并堆维护当前点向上延伸的所有链长,以及最小代价,合并时对每个儿子的堆里所有元素加上其它儿子的代价,当堆顶的链不能再向上延伸时,弹出即可。
CF671E Organizing a Race
CF643D Bearish Fanpages
CF643F Bears and Juice
CF643G Choosing Ads
发现 \(⌊\frac{100}{p}⌋\) 很小,考虑暴力维护,记录当前的 \(⌊\frac{100}{p}⌋\) 个答案,摩尔投票即可。
CF679E Bear and Bad Powers of 42
暴力枚举射击顺序,挨个判断即可。
CF685C Optimal Point
如果 \(s_{i-1}\) 不是 \(s_{i}\) 的后缀,将 \(s_{i}\) 后面多余的部分删掉显然不劣,建 \(\text{SAM}\) ,\(\text{parent}\) 树上 \(dp\) 即可。
CF696F ...Dary!
CF698D Limak and Shooting Points
CF700E Cool Slogans
CF704B Ant Man
CF704C Black Widow
CF704D Captain America
CF704E Iron Man
CF708D Incorrect Flow
注意到,只要 \(f\) 在 \(0 \sim c\) 内,就可以用 \(1\) 的代价更改,但是一旦要超过 \(c\),就需要同时更改 \(c\),相当于代价为 \(2\) 。
对 \(f \le c\) 的边和 \(f > c\) 的边分开考虑:
如果 \(f \le c\),则最终的 \(f'\) 可以减小或增大,故连如下三条边:
-
减小 \(f\):也就是从 \(v\) 到 \(u\) 退流,连 \(v \to u\),容量为 \(f\),费用为 \(1\)。
-
增大 \(f\)(\(f \le c\) 的部分):连 \(u \to v\),容量为 \((c - f)\),费用为 \(1\)。
-
增大 \(f\)(\(f > c\) 的部分):连 \(u \to v\),容量为 \(\infty\),费用为 \(2\)。
如果 \(f > c\),则至少要花费 \((f - c)\) 的代价,且在 \(c \le f' \le f\) 时取到,故先贡献 \((f - c)\),连如下三条边:
-
减小 \(f\),最终的 \(f'\) 在 \(c \sim f\) 之间:连 \(v \to u\),容量为 \((f - c)\),费用为 \(0\) 。
-
减小 \(f\),最终的 \(f' \le c\):连 \(v \to u\),容量为 \(c\),费用为 \(1\) 。
-
增大 \(f\):连 \(u \to v\),容量为 \(\infty\),费用为 \(2\)。
然后对于初始的每条边,连 \(u \to v\),容量下界和上界均为 \(f\),费用为 \(0\)。
CF708E Student's Camp
对于每一行,先考虑算变成区间 \([l,r]\) 的概率。
设 \(k\) 天内,消失 \(i\) 个格子的概率为 $ g_i = {k\choose i} p^i \times (1-p)^{k-i}$ 。
所以剩下区间 \([l,r]\) 的概率为 \(g_{l-1} \times g_{m-r}\) 。
当然还需要检查这段区间长度是否合法,因为最多消失 \(2k\) 个格子。
转移式子不难写出。
复杂度 \(O(nm^4)\) ,显然不行,而且状态数都为 \(O(nm^2)\) 。
那考虑优化状态,去掉左端点的限制。
设 \(dp_{i,r}\) 表示第 \(i\) 行的剩余区间的右端点为 \(r\),第 \(0\) 行到第 \(i\) 行都联通的概率,转移的时候枚举 \(l\) 进行转移。
它满足 \(r_1 \geq l, l_1 \leq r\) ,那么容斥把这一部分算出来即可。
对于 \(r_1 < l\) 的部分,枚举 \(l\) 时计算 \(\sum_{j=1}^{l-1} dp_{i-1,j}\) 。
对于 \(l_1 > r\) 的部分,因为网格是对称的,所以 \(f_{i,r}\) 也可以表示左端点为 \(m-r+1\) 且联通的概率,因此这一部分可以计算为 \(\sum_{j=1}^{m-r} f_{i-1,j}\) 。
于是转移如下。
考虑前缀和优化。
令 \(s_{j}\) 表示 \(\sum_{k=1}^j f_{i-1,k}\) 。
在令 \(p_i\) 和 \(q_i\) 依次为 \(g_i\) 与 \(g_i \times s_i\) 的前缀和,之后即可做到 \(O(1)\) 转移,总时间复杂度 \(O(nm)\) 。
[AGC020D] Min Max Repetition
[AGC020E] Encoding Subsets
容易想到一个区间 \(dp\) ,可以使用 \(\text{__int128}\) 进行记忆化搜索,状态数很少。
[AGC020F] Arcs on a Circle
首先断环为链, 以最长的弧的起点作为链的起点(同时也是链的终点), 由于将环的的问题转化为了线段的问题, 下面将弧描述为线段.
然后由于坐标的连续性为求解带来的困难, 我们需要将坐标离散化, 套路化的方法是将坐标 \(x\) 分为整数部分 \(a\) 和小数部分 \(b\) , 对小数部分进行离散化。
离散化之后, 坐标变为 \(nc\) 个, 这个问题就可以比较容易的解决了。 \(\mathcal O(n!)\) 地枚举各个线段小数部分的相对大小, 然后状压 \(\text{DP}\) 一下就好了。
[AGC021E] Ball Eat Chameleons
既然是对球的颜色序列计数,那么就只需要考虑,对于每一个颜色序列,判断它是否可行。
假设总共喂了 \(R\) 个红球和 \(B\) 个蓝球,满足 \(R + B = K\) 。
首先考虑一只变色龙在什么情况下最终才会变成红色:
-
它吃的红球比蓝球多。
-
它吃的红球和蓝球一样多(且不为 \(0\) 个),但是吃的最后一个球是蓝球。
如果 \(R < B\),也就是红球总数比蓝球少,那么显然无解。
如果 \(R \ge B + N\),也就是红球比蓝球还多 \(N\) 个,可以直接让每只变色龙吃的红球都比蓝球多,一定有解。
否则 \(B \le R < B + N\),就只能让一些变色龙吃的红球和蓝球一样多,另一些变色龙红球吃的更多一些。
对于一种方案,我们进行调整:
如果某一只变色龙吃的红球比蓝球多两个以上,可以拿出一个红球分配给别的变色龙。
这样调整之后,就一定是:一些变色龙吃的红球比蓝球多恰好一个,另一些一样多。
令 \(R\) 表示一个红球,\(B\) 表示一个蓝球。
也就是恰好有 \(R - B\) 只变色龙多吃一个 \(R\),其它 \(N - (R - B)\) 只变色龙吃的一样多。
如果 \(R = B\),也就是 \(R - B = 0\),不存在多吃一个 \(R\) 的变色龙,那么考虑吃掉了最后一个球的变色龙,那么最后一个球必然是 \(B\),那么去掉这个蓝球,就等价于 \((R, B - 1)\) 的情况。
那么现在就至少有一只变色龙多吃一个 \(R\),对于吃的一样多的变色龙,可以再调整:
如果它吃的不是恰好两个球(\(RB\)),那么可以在最后一个字符前取出一个 \(R\) 和一个 \(B\),分给多吃了一个 \(R\) 的变色龙。
那么现在就变成了,每只吃的红球和蓝球一样多的变色龙,吃球的顺序都是 \(RB\),它们的个数为 \(N - (R - B)\) 。
然后剩下的 \(R - B\) 只变色龙,就可以直接每只多吃一个 \(R\) 然后满足条件了。
综上所述:对于 \(B < R < B + N\) 的情况,满足条件当且仅当能够取出 \(N - (R - B)\) 对 \(RB\)(有顺序)的子序列。
这等价于:对于每个前缀,这个前缀中的蓝球比红球最多多 \(B - (N - (R - B)) = R - N\) 个。(就是说这个前缀中无法参与匹配的蓝球数量不能超过 \(R - N\) 个)
换句话说,令 \(R\) 为 \(+1\),\(B\) 为 \(-1\),则任意一个前缀和都应该要大于等于 \(-(R - N)\) 。
可以看成从 \((0, 0)\) 向右(\(R\))或向上(\(B\))走到 \((R, B)\),但是不能到达直线 \(y = x + (R - N)\) 的严格上方。
这是一类经典的组合问题,类似于卡特兰数的计算方法(翻转第一次碰到直线上方的部分),可以得到答案:
枚举 \(R\)(\(B = K - R\))计算组合数即可得到答案。
[AGC021F] Trinity
首先注意到行和列的差异性,行只要求记录最小的列标,所以我们可以将此视作一种阶段。更具体的我们一列一列的填,每一次在第 \(i\) 列确定对于 \([1,n]\times[1,i]\) 这个列前缀矩阵相对于 \([1,n]\times[1,i-1]\) 的非 \(0\) 行集合的变化,设此变化为 \(S\to T\) 则 \(\forall x \in T / S,A_x\leftarrow i\) 。
设 \(f_{i,j}\) 表示 \([1,n]\times[1,i]\) 即前 \(i\) 列中非 \(0\) 行集合大小为 \(j\) 的方案数,假设每一轮增加 \(\Delta j\) 个,那么这一步我们需要选出这 \(\Delta j\) 个新增的数具体对于现在已经有的 \(j+\Delta j\) 个数他们是谁(这一步确定了 \(A_x,x\in T/S ,|T/S|=\Delta j\),附加上最值选取的相对于已经有的 \(j+\Delta j\) 个数是谁(这一步确定了 \(B_i,C_i\) )
(刚刚上方描述的 [他们是谁] 其实都是在刻画相对大小关系确定,每一步都确定后答案取出时乘上的组合数表示选出最终确切的值就可以反推回去每一步的确切选取了)
-
\(\Delta j=0\)
-
那么我们只需要选出最值即可,可以为空,一个相同的数或两个不同数 ,方案数为 \(1+j+\binom{j}{2}\)
-
\(\Delta j\neq 0\)
-
最值贡献均来自这 \(\Delta j\) 个数,那么我们只要选出这 \(\Delta j\) 个数是谁就可以了,方案数为 \(\binom{\Delta j+j}{\Delta j}\)
最值贡献有一个来自 \(\Delta j\) 个数,注意到这个方案与选出 \(\Delta j+1\) 个数构成双射,区分一下最大最小值有一个 \(2\) 的贡献,方案数为 \(2\binom{\Delta j+j}{\Delta j+1}\) 。
最值贡献均不来自这 \(\Delta j\) 个数,类似的有方案数为 \(\binom{\Delta j+j}{\Delta j+2}\)
求一下和即为 \(\binom{\Delta j+j+2}{\Delta j+2}\),也就是大多数人用组合意义解释的系数
最后写一下式子
答案为 \(\displaystyle \sum\limits_{i=0}^{n}\binom{n}{i}f_{m,i}\)
还是写一下,怕不过,简化一下式子后化简得
令 \(\displaystyle F^{[i]}(x)=\sum_{j=0}^n \frac{f_{i-1,j}}{j!}x^j,G^{[i]}(x)=\sum_{j=0}^n \frac{1}{(j+3)!}x^j\)
则
\(\text{NTT}\) 即可做到 \(\mathcal O(nm\log n)\) 。
[AGC022D] Shopping
先可以把 \(\lfloor {t_i\over 2L}\rfloor\) 加入答案,然后把 \(t_i\) 模上 \(2L\) ,这样答案显然不变,并且可以使 \(t_i<2L\) 。
由于最终要回到 \(0\) 处, 跑的路程必定是 \(2L\) 的整数倍,所以我们只需要求火车最少跑多少来回即可(记为 \(ans\))。
首先我们给答案确定一个上界并构造方案。
我们先走到商场 \(1\) ,停留 \(2L\) 后必然购物完,且火车恰好经过,那么乘上火车到下一个商场,反复这么做,直到在第 \(n\) 个商场购物完后就回到 \(0\) 。这样的答案是 \(n+1\) 。
考虑优化方案以达到最优。
我们设 \(l_i\) 表示从左边到 \(i\),列车下次(从右边)经过 \(i\) 的时候是否购完物。类似定义 \(r_i\)。显然 \(l_i=[2(L-x_i)\geqslant t_i],r_i=[2x_i\geqslant t_i]\) 。
显然对于 \(l=r=0\) 的点, 只能在商场 \(i\) 停留 \(2L\) 所以没有优化的余。
若存在一组 \(i,j\) 满足 \(i<j,r_i=l_j=1\),我们对原方案进行修改: 在从商场 \(i-1\) 到商场 \(i\) 的过程中间先走完商场 \(j\) ,那么这样路程不会变多。我们白嫖了这个商场 \(j\) 。所以可以把这样 \(i, j\) 匹配起来,那么答案就减少最大的匹配数。
另外我们发现对于 \(l=1,r=0\) 的商场有 \(2(L-x)\geqslant t,2x\leqslant t\) ,可得 \(x\leqslant \min\{\frac t2,L-\frac t2\}\leqslant\frac L2\)。同理对于 \(r=1,l=0\) 的商场有 \(x\geqslant \frac L2\),故这两种点不可能匹配起来。
那么我们用 \(l=r=1\) 和上述两种点尽量匹配,剩余的再两个两个匹配就好了。
另外,若 \(l_n=1\) ,我们在商场不需要等 \(2L\) ,火车从右边经过时直接上车就好了。
本题有许多细节(可能有的上面都没有提到,譬如商场 \(n\) 是不会被白嫖的等),需要考虑清楚。
时间复杂度 \(O(n)\) 。
[AGC022E] Median Replace
[AGC022F] Checkers
根据删除操作连边,不难看出最后会形成一棵树,对于一条边不妨将留下的那个点作为父亲,根也就是最后剩下的点。
我们会发现,无论大小关系如何,假设我们是要求 \(a\) 对于 \(b\) 对称后的点,那么总有 \(val_a \leftarrow 2val_b-val_a\) ,其中 \(val_i\) 表示点 \(i\) 当前的值。
我们考虑直接写出根最后的结果,一定会是形如 \(\sum\limits_{i=1}^{n}{c_i2^{d_i}x^i}\) 的形式,其中 \(c_i\) 为一个系数,取值为 \(1\) 或 \(-1\) ,\(d_i\) 为点 \(i\) 在树上的深度。
同时可以发现 \(2^n \ll x\) ,也就是说,在这个计算式中,任意两个点对最终结果的贡献不会被抵消,所以原问题等价于对于 \(n\) 个二元组 \((c_i,d_i)\) 的不同方案的计数。
我们会发现,\(d_i\) 的实质是每个深度有多少个点而不是树的形态,意思是我们可以先钦定好树的每个深度有多少点后再用多重组合数的形式来确定每个点上放哪个值。
接下来再考虑 \(c_i\) ,手玩后不难发现影响 \(c_i\) 的值的因素只有两个,点 \(i\) 的儿子的个数和每个祖先在选完与使点 \(i\) 和该祖先相连的链之后再选则其它儿子的儿子个数,也就是 \(c_i=(-1)^{\text{儿子个数+每个祖先在选完与其相连的链后继续选的儿子个数}}\) ,此处建议读者自行画一个树模拟一个点在按操作顺序操作后会被哪些点影响。
以下我们为简便直接称 \(c_i\) 为点 \(i\) 的权值,由于一个点的权值只会和儿子与祖先相关,所以如果我们在最后一层加上一个点,影响到的只会是其父亲以及其先前加入的兄弟节点,对于其以后可能的儿子则不做考虑。
所以我们能发现我们并不在乎一个点的权值究竟是 \(1\) 还是 \(-1\) ,只需要知道它的权值是否与父亲相同就可以确定二元组了。
考虑 \(dp\) ,设 \(f_{i,j}\) 表示已经考虑了 \(i\) 个点且树的最后一层有 \(j\) 个点的儿子数为奇数的方案,这里这样设计状态的原因是方便确定树的大致形态而不必精细,即方便计算多重组合数,算是一个套路,转移方法也是套路。
我们可以发现如果一个点有 \(x\) 个儿子,那么儿子中有 \(\lceil \frac{x}{2} \rceil\) 个点的权值与父亲不同,按加入顺序编号会是奇数编号的点。
转移时就枚举下一层的点数 \(k\) ,可以推出在不考虑该层点儿子的情况下有 \(\lfloor \frac{j+k}{2} \rfloor\) 个点的权值与其父亲不同。
但是显然不一定有这么多点的权值与父亲不同,因为有儿子的影响还没算上,所以我们再枚举算上儿子后和父亲权值不同的点的个数 \(l\) ,那么这一层就应该有 \(|l-\lfloor \frac{j+k}{2} \rfloor|\) 个点的儿子数是奇数。
所以转移就是 \(f_{i+k,|l-\lfloor \frac{j+k}{2} \rfloor|} = f_{j+k,|l-\lfloor \frac{j+k}{2} \rfloor|}+f_{i,j}\times \binom{i+k}{i}\times \binom{k}{l}\) ,\(\binom{i+k}{i}\) 是多重组合数带着算。
时间复杂度为 \(\mathcal{O}(n^4)\) 。
[AGC023D] Go Home
[AGC023E] Inversions
考虑总方案数是:
我们令 \(a_i\) 的排名为 \(b_i\) ,\(c_i\) 为排好序后的 \(a_i\) ,即:
考虑每两个位置的对于逆序对的贡献,不妨先设这两个位置为 \(i\) ,\(j\) 。
若 \(j<i\) 且 \(a_j<a_i\) ,我们求其的逆序对贡献。
由于是逆序对,所以 \(a_i\) 比 \(a_j\) 大的部分可以省去,然后发现就是这样?
这个式子的组合意义实际上就是求出在 \(a_i\) 与 \(a_j\) 相同的时候的总方案数,然后除以 \(2\) ,就是 \(p_j>p_i\) 的方案数了。
若 \(i<j\) 且 \(a_i>a_j\) ,我们可以求其的顺序对贡献,用总的减去它。
发现对于前后的,只有一小部分不一样,我们考虑先来处理共同部分:
前面的这个东西对于每一个 \(i\) 都是一样的,后面的一半可以用线段树来维护,我们考虑从小到大往线段树中添加东西,对于当前位置 \(i\) ,令其排名为 \(k\) ,排名比其小的部分已经在线段树中了,我们考虑直接提取出区间和,然后对于全局进行一个区间乘 \(\frac{c_k-k}{c_k-k+1}\) ,同时将位置 \(i\) 的部分改为 \(a_i-b_i\) 就可以了吧。
[AGC023F] 01 on Tree
[AGC024D] Isomorphism Freak
[AGC024E] Sequence Growing Hard
大概是一个比较不同的二维 \(dp\) 的切入方法。
先考虑一个弱化版的问题:给定 \(A_n\) ,求有多少种可能的序列组 \(A_0,\cdots,A_{n-1}\) 。
我们发现,由 \(A_n\) 得到 \(A_0\) 的过程相当于每次从 \(A_n\) 中删一个数,并要求字典序递减。
「字典序递减」看上去不是很好处理,于是考虑其是否存在等价条件:假如我们删了 \(s\) 的第 \(i\) 个位置得到了 \(s'\) ,可以发现,\(s\) 的前 \(i - 1\) 个位置构成的前缀和 \(s'\) 的前 \(i - 1\) 个位置构成的前缀完全相同,我们实际上需要比较的是这两个串从 \(i\) 开始的后缀的字典序。
注意到我们有 \(s_{j+1}=s'_{j}(j\ge i)\),想象一下比较字典序的过程:
若 \(s_i = s'_i = s_{i+1}\) ,则比较位置 \(s_{i + 1}\) 和 \(s'_{i+1}\) 。
若 \(s_{i+1} = s_i = s'_{i+1} = s_{i+2}\) ,则比较位置 \(s_{i+2}\) 和 \(s_{i+2}'\) 。
...
故「\(s\) 删去第 \(i\) 个元素后字典序变小」的条件实际上等价于:「\(s_i\) 大于 \(i\) 之后第一个不等于 \(s_i\) 的元素」。
但是,我们注意到,如果 \(s\) 存在一段相同的元素,那么删除这段元素中的任何一个所得到的结果完全相同,它们不应该被重复统计,所以我们不妨给这段元素人为地定一个顺序:直觉告诉我们,定义每次只能删除一段连续元素中最右边的元素是最为方便的。
然后,我们再重新审视一下我们的条件,发现它惊人的简洁:「\(s_i > s_{i+1}\) 」(当然,最后一个元素是一定能删的)。
于是我们考虑 \(dp\),设 \(f_{i,j}\) 表示长度为 \(i\) 的 \(A_i\) ,只用了 \([1,j]\) 中的整数的方案数。
转移的时候,为了避免重复,我们枚举第一个 \(1\) 出现的位置 \(k\),以及这个 \(1\) 被删除的时刻 \(p\)。那么就意味着:\(1\) 后面的 \(i - k\) 个数必须在前 \(p - 1\) 个时刻中全部被删除。
于是有:
注意到 \(\sum {p-1\choose i-k}\) 只和 \(i,k\) 有关,而与 \(j\) 无关,所以可以预处理,时间复杂度就做到了 \(\mathcal O(n^3)\) 。
然后这题就做完了。
[AGC024F] Simple Subsequence Problem
[AGC025D] Choosing Points
[AGC025E] Walking on a Tree
记 \(c_e\) 表示边 \(e\) 被路径经过了多少次,答案的上界显然是: \(\sum_{e\in E} \min\{2,c_e\}\) 。
下面将连接 \(u,v\) 的边记为 \((u,v)\) ,端点为 \(u,v\) 的路径记为 \([u,v]\) (中括号内顺序不体现方向)。
考虑下述构造方法:
任取一个叶子节点 \(u\) ,记 \(u\) 的父亲节点为 \(v\) 。
若 \(c_{(u,v)}=0\) ,直接删除 \(u\) 和 \((u,v)\) 对答案没有影响。
若 \(c_{(u,v)}>0\) ,覆盖 \((u,v)\) 的路径必然是 \([u,a]\) 的形式(有一端为 \(u\) )。
若 \(c_{(u,v)}=1\) ,\((u,v)\) 的贡献与 \([u,a]\) 方向无关,把 \([u,a]\) 改成 \([v,a]\) 后删除 \(u\) 和 \((u,v)\) ,显然对答案没有影响。
若 \(c_{(u,v)}>1\) ,我们任取两条经过 \((u,v)\) 的路径 \([u,a],[u,b]\) 分别定向为 \(u\to a,b\to u\) ,设 \([u,a],[u,b]\) 的分叉点为 \(d\) ,则 \(u\) 到 \(d\) 的所有边的贡献都为 \(2\) ,两路径分叉后的部分可以等价与一条路径 \([a,b]\) ( \([a,b]\) 走向制约 \([u,a],[u,b]\) 走向) 。剩下的路径用与 \(c=1\) 相同的方式传递给 \(v\) 即可。
不断执行直到只剩下一个点。
不难发现通过上述方法构造的方案满足边的贡献都为 \(\min\{2,c\}\) ,权值和达到了上界,故最优。
对每个点,用 \(\text{set}\) 维护一下以这个点为端点的路径即可很容易地模拟上述操作。
时间复杂度 \(\mathcal O(n(n+m)\log m)\) 。