Hey Gift:挥霍仅此一次的青春岁月
做题记录 again。
P6187 [NOI Online #1 提高组] 最小环
自己想出来的。很牛啊!
首先发现把所有互相距离为 \(k\) 的元素拿下来,相邻的元素之间连边,你会得到 \(\gcd(n,k)\) 个环(一开始以为是 \(k\) 个……有点菜啊),当环数为 \(1\) 时答案与 \(k=1\) 无异(本质上就是相连的两个数相邻),所以我们考虑 \(k=1\) 怎么做。
不知道为什么可以想到观察打表可以想到增量构造法。考虑先将 \(a\) 排序,显然 \(n=3,k=1\) 时的一种最优构造是 \(a_1,a_2,a_3\),下一次放入 \(a_4\) 的时候必然放在 \(a_2,a_3\) 中间最好,\(a_i\) 必然放在 \((a_{i-2},a_{i-1})\) 之间最好。还可以发现这个构造非常优美,我们上一步的构造总是能够使下一步操作合法!于是我们就会了 \(k=1\),也就是所有 \(\gcd(n,k)=1\)。
证明:考虑 \(a_1,a_2,a_3\),将 \(a_4\) 放入 \((a_1,a_2)\) 中间对答案产生 \(a_4\times (a_1+a_2)-a_1\times a_2\) 的贡献,放入 \((a_2,a_3)\) 中间对答案产生 \(a_4\times (a_2+a_3)-a_2\times a_3\)。后者与前者作差得到 \((a_4-a_2)(a_3-a_1)\),显然这个积总是 \(>0\),所以可以推广开来,\(a_i\) 放在 \((a_{i-2},a_{i-1})\) 中间是最优方案。
考虑 \(\gcd(n,k)\neq 1\) 怎么做。显然每个环的大小都是一样的,所以此时环长为 \(l=\frac{n}{\gcd(n,k)}\),很容易猜到将原序列排序之后每 \(l\) 一段,每个环独占一段,然后做一个 \(k=1\)。因为 \(\gcd(n,k)\) 总是 \(n\) 的因数,记忆化每个 \(\gcd(n,k)\) 的答案,暴力即可做到根号时间复杂度。根号比较好写。
当然你也可以考虑每一段都只会相对 \(k=1\) 多出 \(\gcd(n,k)-1\) 个断点,只维护这些断点并维护与 \(k=1\) 时答案的差异即可做到调和级数。
关于独占一段的正确性证明可以看 EI 的题解。
P2512 [HAOI2008] 糖果传递
超级典题,但是我觉得很难啊。/kk
考虑这样一个套路:\(x_i\) 表示每个位置向左给多少值,\(x_i>0\) 表示给出去,\(x_i<0\) 表示拿过来,这样就能表示相邻两个位置之间值的转移,也就能表示一个位置上最终的值,是 \(a_i+x_{i+1}-x_i\)(当然,对于 \(i=n\) 是 \(a_i+x_{1}-x_i\))。
这个套路出现在 P1031 [NOIP2002 提高组] 均分纸牌 中。你考虑算出每个位置的初值距离平均值的差,鉴于 \(1\) 只能从右边得到纸牌达成目标,从左到右依次枚举 \(i\) 做,保证前 \(i-1\) 位都已经合法,再通过操作 \(i+1\) 让 \(i\) 合法就可以了。
你会发现一来的这个作差操作本质和我们这个设 \(x\) 差不多。那么环形均分纸牌怎么做呢?
考虑方程:
显然这个方程解不了,我们考虑换元,扔掉最后一个特殊的方程,然后把它全部换成 \(x_1\)。
向上进行递归带入可以得到这么一个式子:\(x_i=x_1+\sum\limits_{j=1}^{i-1}\overline{a}-a_j\)。
很明显后面整个和式我们是已知的,不妨设 \(c_i\) 代替掉这个和式:
于是又可以得到 \(x_i=x_1-c_i\)。尝试写出答案:
将绝对值看做数轴上两点距离,由初一数学可得,当 \(x_1\) 取 \(c\) 中位数时,距离和最小。因此给 \(x_1\) 取 \(c\) 中位数后直接算答案即可。
P3745 [六省联考 2017] 期末考试
有点小清新!
一眼望过去好像是巨大分类讨论题,冷静下来会了 \(A\geqslant B\)。怎么都不会 \(A<B\),想了想大概是一个很晚的课程和一个很早的课程互补,但是不知道怎么补可以结束……看了题解表示自己很憨。
首先,你要牢记这样一个事实:所有的学生的课程都是一样的,是所有课程,等待的时间取决于最晚的课程。(我不知道为什么一直没有从这个角度入手……)又注意到 \(t\) 很小,所以很自然地可以想到枚举最晚课程的时间 \(x\)。那么学生的不愉快度的贡献就是 \(\sum\limits_{i=1}^n\max(0,x-t_i)\times C\),这个容易前缀和出来。
然后你考虑 \(A\geqslant B\),很明显这种情况下用 \(B\) 严格用于用 \(A\),所以你直接把所有时间比 \(x\) 晚的全部提前过来就好了。\(A<B\) 肯定是先用一些 \(A\),不行了再用 \(B\),直接考虑 \(x\) 前出成绩的课程有多少空间可以延后,\(x\) 后出成绩的课程总共需要提前多少,讨论一下就完了。
P2672 [NOIP2015 普及组] 推销员
考虑贪心。一开始写了个伪算过了所有除了最后一个 Hack 的测试点……气死我了!最后发现方向完全想错了。
首先把所有人按照他们的推销贡献排序,有一种很显然的想法是直接取前 \(X\) 大然后加上距离最远的那个的距离贡献。然而这样有点问题,有可能可以舍弃掉前面最小的一个,去换一个距离比较远但是推销贡献不大的,靠距离贡献成为最大。
可以证明只会舍弃一个。
假设舍弃两个,那么我们需要在距离更远,且推销贡献更小的人当中选两个,得到的距离贡献是且仅是他们两者中更远的那个造成的,较近的那个只会造成推销贡献,那显然不如撤销较近的那个。如果距离相等,撤销掉推销贡献更小的那个也一定更好。舍弃两个不行,两个以上显然就更不行了。
对于第一类直接取 \(X\) 大的,从大到小排序之后维护一下前缀推销贡献和、前缀最大距离即可算出答案。对于第二类,还是从大到小排序,只取 \(X-1\) 大的推销贡献加上后面的最大单个总贡献(二倍距离加推销贡献)即可。
为什么可以加后面最大的单个总贡献?
万一后面最大的单个总贡献的距离已经被前 $X-1$ 大包含了不就算少了吗???事实上,如果它被包含了,那么它对答案的贡献一定严格不优于直接取前 \(X\) 大(距离一定不比它短,推销贡献一定不比它小),所以无所谓。
P6787 「SWTR-6」Snow Mountain
感觉不难想啊……可能是因为太懒了不想做了所以没有认真想?
一眼排序,先不考虑不允许的限制,很容易想到一个看着对得不能再对的傻逼贪心就是对折配对,但是要先从中间开始因为要乘上操作次数。因为 \(n\) 是偶数所以一定可以配完。
接下来考虑有限制怎么办。首先题目有一个很鬼畜的限制就是一个数最多只和一个比它大的数被禁止,那么你继续考虑对折配对,所谓对折其实就是把这个序列分成了等长的前半段和后半段,我想让前半段和后半段匹配。你再仔细一想,你发现我干嘛必须对折呢?贡献是两者的最小值,意思就是说我只要让前半段从大到小匹配,然后每次匹配其实可以在后半段里面随便选的!于是你又有了一个想法是干掉那些与别的水晶组成禁止关系的后半段水晶:随便用一个前半段的和它不被禁止的水晶把它干掉,这样有一些水晶就自由了。
顺便考虑无解怎么判定。你发现无解肯定当且仅当有个水晶无论怎么办都不能被摧毁,那么它一定被其他所有水晶都禁止掉了。除了这种情况都有解。
下面继续考虑如何在有解的情况下最小化贡献。
题解说每次匹配掉那个被禁止次数最多的水晶,这样放出来的自由的水晶是最多的,如果有多个就选择 \(a\) 值最小的那个……
好的我不会这题。贪心真奇妙。
CF559C Gerald and Giant Chess
你是傻逼,当初没有认真学会这个做法。
考虑容斥,斥掉经过至少一个黑格子的路径。
你很容易想到 Key Cup T2,然而这次你再也不能 \(\mathcal O(n^3)\) 了。我们还是钦定一条路径只在它第一次经过黑格子时去掉,那么设 \(f_i\) 表示第一次经过的黑格子是格子 \(i\) 的路径数。
首先,经过这个黑格子之后后面随便走都无所谓了,很明显组合数即可。考虑怎么求出到达这个格子不经过其他黑格子的方案数。还是容斥,先组合数算出任何到达 \(i\) 格子的所有路径数,然后斥掉经过别的黑点到达它的路径数。这种路径我们仍然只考虑在第一次经过黑格子时计数,那么很明显到达它能经过的黑点必然横纵坐标都小于等于它,所以找出这样的点 \(j\) 作为起点,用它们的 \(f_j\) 乘上 \(j\to i\) 的方案数就是需要从 \(f_i\) 中减掉的部分。
对于每个点做起点求一下和减掉就做完了。
CF621E Wet Shark and Blocks
又被踩了……我不会矩阵优化。
显然有一个 dp 式子是 \(f_{i,(10j+p)\bmod x}\gets f_{i-1,j}\times cnt_p\),注意到每相邻两项转移是相似的,并且 \(b\) 很大,考虑矩阵优化。
然后就不会了。
我们把 push 的递推方式改成 pull 的,显然这样才是矩阵优化更加容易的方式,那么很容易得到 \(f_{i,q}\gets \sum\limits_{(10j+p)\equiv q\pmod x} f_{i-1,j}\times cnt_p\)。因为你想让 \(f_{i-1}\) 的每一项都乘上一个数,于是很容易想到把 \(f\) 构造成一个行向量。这样矩乘的时候左边总是一整行和右边的一列依次乘。然后你考虑右矩阵哪些位置上是要有值的。
想象矩阵乘法过程。左矩阵拿出第一行的第 \(j\) 列元素出来(\(f_{i,j}\)),与右矩阵的第 \(q\) 列第 \(j\) 行元素相乘,再对于每一个 \(j\) 加和得到新矩阵的第一行第 \(q\) 列(\(f_{i+1,q}\))。所以一个位置 \((j,q)\) 有值当且仅当存在一个 \(p\) 满足 \((10j+p)\bmod x=q\)。所以在 \((j,(10j+p)\bmod x)\) 的位置放上 \(cnt_p\) 就行了。
还可以这样想。对于每个 \(i\to i+1\) 的转移,都是 \(f_{i,j}\) 同时转移,所以需要把它们看成一个状态,写进一个矩阵。因为新状态是从许多旧状态转移过去的,所以需要把这些同时对一个状态做贡献的状态写在左矩阵的一行上才能同时算到贡献(bonus:如果一个状态乘多个值做贡献,就在右矩阵加很多列)。
菜得不行……
CF1866G Grouped Carriages
不会贪心,可以去死吗?
一眼二分,要求每个车厢的人数都不超过 \(mid\)。这里一直在思考怎么搞定多出人的车厢,只想到了把每个车厢的人看成一个区间。
先把所有人都请下车,考虑从左往右安排车厢里的人,很明显这个车厢里的人必须来自那些区间包含它的车厢里的人。所以考虑把所有包含该车厢的区间拿出来,显然按右端点排序之后优先满足靠前的区间,写个数据结构维护一下就完事了。
CF1765L Project Manager
好题。
首先注意到有用的工作日不会太多,因为最多一个项目拖 \(7\) 天之后一定会有进度,一个假期最多跳掉 \(7\) 天,所以 \((7+7)\times 2\times 10^5\) 天之后一定能做完所有项目。
这启发我们按照时间一天一天模拟。遇到假期跳掉就好了。
我们考虑一天之中会发生的事情。我们首先需要找出在这一天可以并且需要工作的人,然后为每一个人准备一个 set
表示现在堆在他身上的的项目,拿出编号最小的项目做了它。这样每一次枚举都能使得一个项目的进度得到推进,枚举次数不会超过 \(2\times 10^5\)。
考虑如何找出这一天可以且需要工作的人。注意到一个人是否可以工作之和星期几有关,所以我们开 \(7\) 个 map
,如果一个人他有 \(x\) 个被安排的工作,因为工作可以在任何一天做,所以必须给他每一个工作日的 map
他的那一项都放上 \(x\),只要每个 map
他的那一项不变成 \(0\) 就说明他有工作要做,应当被枚举到(同理,枚举到他做工作和项目推进是等价的,次数不会超过 \(2\times 10^5\))。
综上所述,我们枚举天数的时候先得到今天是星期几,然后把今天的 map
里面有的人全部拿出来,把他们 set
里面第一项的项目推进一下。注意一个人做了一样工作之后,所有 map
中他的这一项都要减少 \(1\),因为他少了一个被安排的工作。如果变成 \(0\) 就需要 erase
掉避免枚举闲人(闲人可能特别多)。
推进项目是简单的,新加入的那些人多了一项被安排的工作,改改每一个 map
再往他们的 set
里面插一下项目就好了。和初始化差不多,因为初始化等价于把项目推进到第一个人的位置。
P2158 [SDOI2008] 仪仗队
首先特判 \(n=1\),然后很快可以发现答案就是 \(1+2\sum\limits_{1}^{n-1}\varphi(i)\)。接下来考虑求欧拉函数前缀和。
显然用不着莫反,欧拉筛再前缀和就可以了(不能埃氏筛!)。
首先我们知道,欧拉函数是一个积性函数,所以考虑唯一分解定理,把 \(n\) 的一个质因子抛掉,有 \(\varphi(n)=\varphi(\frac{n}{p^k})\cdot \varphi(p^k)\),右边那个 \(\varphi(p^k)\) 显然因为每个含有 \(p\) 因子的数都不与 \(p^k\) 互质,其他数都与 \(p^k\) 互质所以是 \(p^k-p^{k-1}\),也就是 \(p^k(1-\frac{1}{p})\)。这样递归分解下去直到 \(1\),可以发现前面的 \(p^k\) 正好又组成了一个 \(n\) 的形式,于是有:
然后你考虑欧拉筛过程。每次我们让一个数 \(ip_j\) 被 \(p_j\) 筛掉,那么你考虑 \(i\) 和 \(p_j\) 的整除关系。
- 如果 \(p_j|i\),那么它贡献 \(p_j\),即 \(\varphi(ip_j)=\varphi(i)\times p_j\),因为它为 \(ip_j\) 提供了一个质因子(之前那个 product 前面有个 \(n\))。
- 如果 \(p_j\nmid i\),那么它贡献 \(p_j-1\),即 \(\varphi(ip_j)=\varphi(i)\times (p_j-1)\),因为它为 \(ip_j\) 提供的那个质因子 \(p_j\) 第一次出现,会被除掉,只剩下一个 \(p_j-1\),而后面再次出现就能正常贡献了。
还是不难理解的。我筛法学的真的差。
CF811E Vladik and Entertaining Flags
好题。
看完题你就有一个大概 \(n\alpha(n)m\sqrt m\) 的莫队加可撤销并查集做法,然而这应该过不了。
你发现这东西可能还挺好合并的,考虑线段树。那么你需要考虑合并的时候会减少的连通块数量,这个很容易想到并查集。很容易发现每次合并只有最左边一列和最右边一列的连通块信息会有变化,中间的列的信息以后都没用了,所以我对于每一个线段树节点上,维护其管理的区间最左边一列每个位置并查集的祖先编号,最右边一列每个位置的并查集祖先编号。然后对于每次 pushup
或者合并答案,先把连通块数量设置为两边之和,然后枚举中间接在一起那两列的每一行,如果左右的数一样,并且他们的祖先编号不同,那么就合并在一起,连通块数量减少 \(1\)。
最后需要更新左儿子左边那一列上的祖先编号和右儿子右边那一列上的祖先编号,成为这个节点的信息。
为什么需要维护祖先编号?
可能会有这种情况:
2222|2222
2111|1112
2222|2222
我们在第一次遇到 2|2
的时候干掉了两边 $2$ 连通块合并带来的重复贡献,然后把它们合并在一起了。这样下一次遇到两个 $2$,因为他们的编号和上面的 $2$ 分别都是相等的,因此会 find
到一样的祖先,就不会统计到了。
为什么最后需要对没有修改的左边的左列、右边的右列进行更新?
可能会有这种情况:
2112|2112
2222|2222
2112|2112
很明显因为我们维护了祖先编号,所以左右儿子的最左最右列都分别有着相同的编号,中间进行合并之后,相当于左边的左列和右边的右列的祖先也被合在一起了,因此要对他们进行更新,认定他们在一个连通块里。
[ARC166D] Interval Counts
二分之后感觉不好 check,考虑贪心。
显然最左侧的点上必须放满 \(y_i\) 条线段的左端点,我们考虑从左到右扫点进行增量构造。
- \(y_i=y_{i-1}\),显然直接把左边的线段拉过来是最优的,因为截断某条线段肯定会减小最小值。
- \(y_i<y_{i-1}\),这里必须要断掉 \(y_{i-1}-y_i\) 条线段,那么为了使得最小值最大,显然需要断掉左端点最靠左的这么多条线段。
- \(y_i>y_{i-1}\),这里需要增加 \(y_i-y_{i-1}\) 条线段,很明显为了使他们尽量长,把它们的左端点放到 \(x_{i-1}+1\) 是最优的。
很容易想到维护一个堆叫做所有还没有被断掉的线段的左端点集合,但是这不可行,因为 \(y\) 很大。但是我们可以发现我们添加的线段左端点是单调的,维护一个队列表示有 \(y\) 条左端点在 \(x\) 的线段,每次拿队首即可。
P4819 [中山市选] 杀人游戏
Tarjan 复习题。
考虑什么是最优策略。注意到有向图,并且人之间有认识关系,很容易想到缩点,这样一个强连通分量总是可以查询一个人就知道整个块的信息。
于是我们得到了一个 DAG,考虑 DAG 上的查询策略,很自然地开始考虑一下入度为 \(0\) 的点。你发现如果入度为 \(0\) 的点都不是杀手,那么你查询其他点肯定不如查这些点,因为查这些点就能知道他们的出点的情况,像拓扑排序一样推就能安全地推出来了;而如果有一个入度为 \(0\) 的点是杀手,那么你无论如何检验其他点也不得不去检验它。综上,直接一上来就检验入度为 \(0\) 的所有点就行了。很明显由于选择这些人互相独立(检验一个人不影响我不知道其他人的信息),在一个人那里去世的概率是 \(\frac{1}{n}\),那么假设有 \(c\) 个这样的点,在检验中去世的概率就为 \(\frac{c}{n}\),所以活下来的概率就是 \(1-\frac{c}{n}\),这也就是答案。
……吗?
那么你无论如何检验其他点也不得不去检验它。
我都检验了其他点了我还检验它干什么?
也就是说,如果存在一个大小为 \(1\) 的强连通分量(如果大小不是 \(1\) 那么也必然至少要在强连通分量里面选一个点,没有区别),满足它入度为 \(0\),并且它所连到的所有点都入度 \(\geqslant 2\),那么我们就可以通过检验其他入度为 \(0\) 的点来排除掉除了它以外的任何点。换句话说,一定可以拓扑到所有除了它以外的点,没有第二个只能通过选了它才能检验到。对于这种情况,答案变为 \(1-\frac{c-1}{n}\)。
实现的时候记得去掉重边。
好题。
P3211 [HNOI2011] XOR和路径
神题!
首先考虑 dp,发现直接整个 \(f_i\) 表示当前在 \(i\) 节点,走到 \(n\) 节点的异或的期望肯定是不行的,直接转移用一个点的期望异或上边权转移过去看起来就很不靠谱,而且难道你拿小数去异或吗。
发现对于这个问题每一位应该是独立的,所以考虑每一位一个 dp 叫做 \(f_u\) 表示 \(u\to n\) 的路径上这一位为 \(1\) 的概率,\(d_u\) 表示 \(u\) 的出度,那么有:
为什么是相对路径顺序倒着设计 dp 并转移的?
你发现沿着路径顺序正着转移时,乘概率会非常麻烦,所以我们在设计 dp 时就把它设计为 $u\to n$ 这样路径后缀的期望,每次在前面加点,只需要乘上加的点的出度分之一,非常 easy。提取公因数 \(\frac{1}{d_u}\),乘到左边去得到:
好好好,但是问题来了,这个图可能有环,怎么转移呢?
拆掉和式,移项得到:
于是我们发现,转移方程上每一个 \(f\) 的系数都是确定的,并且常数项也是确定的,那么我们就可以把 \(n\) 个点的 \(n\) 个转移方程排在一起,解方程确定 \(n\) 个未知数 \(f\)。
特别地,第 \(n\) 个点的方程应当只留下一项,表示 \(f_n=0\)。
高斯消元,启动!
因为一定客观存在这样一堆 \(f\) 满足条件,所以显然是不会无解的。在图连通的情况下,也不会解出自由元。
这题很阴间,精度要求很高。需要注意消元方式和 eps
大小。还要注意自环只能相当于一条单向边(不难理解,两条边本质相同)。
P3232 [HNOI2013] 游走
我以为会做上面那道题就应该会做这道的。
显然,得分的总期望就是每一条边的编号乘上每一条边被经过的期望次数。于是要算出每条边的期望次数。
首先想到了这样一个办法:\(f_{u,i}\) 表示 \(u\to n\) 情况下边 \(i\) 的期望经过次数,转移比较显然,最后高斯消元解就行了。然而复杂度是错的:边数太大了。
注意到一个比较显然的事实:经过一条边 \((u,v)\) 的期望次数 \(E'(u,v)\) 只和经过 \(u,v\) 的期望次数 \(E(u),E(v)\) 有关,经过其他点的期望次数与这条边毫无关系。具体来说可以发现,到达 \(u\) 处的期望次数如果是 \(E(u)\) 的话,那么走上 \((u,v)\) 的期望次数就应该加上 \(\frac{E(u)}{deg_u}\)。进一步我们容易发现 \(u,v\) 两边是独立的,所以可以得到:
问题变为计算 \(E(u),\forall u\in[1,n]\)。
这个容易直接使用 trick 得到,令 \(f_i\) 表示 \(i\) 点的期望经过次数,那么有:
特别地,\(f_n=0\),因为我们不能从 \(n\) 点离开,它的经过次数不能做任何贡献。
P2973 [USACO10HOL] Driving Out the Piggies G
拜谢 Chery 选题。拜谢 dyx 笔记。
首先你有一个显然的想法是 \(f_u\) 表示炸弹在 \(u\) 处爆炸的概率,那么:
这很好理解,但这是错的。
为什么?
最关键的问题:炸弹在 $u$ 处爆炸的概率加上炸弹在 $u$ 处不爆炸的概率根本就不是 $1$。因为炸弹光是走到 $u$ 都会有一个概率的系数。既然要先让炸弹走到 \(u\),我们很容易想到一个理解是:炸弹在 \(u\) 处爆炸的概率就是炸弹走到 \(u\) 的期望次数乘上炸弹爆炸的概率。
证明?
在一个点爆炸的概率等于这个点的期望经过次数乘上每次炸弹爆炸的概率。这样感性理解一下可能能觉得是对的。这里写一下一个简单的,不那么偏感性的解释:
显然炸弹爆炸的次数的取值只有 \({0,1}\)。这样我们发现,炸弹的期望爆炸次数与爆炸概率在数值上相等。
从而,在一个点爆炸的概率 = 期望在这个点爆炸的次数 = 期望经过这个点且在这个点爆炸的次数。
当随机变量 \(X\) 和 \(Y\) 互相独立时 \(E(XY)=E(X)\cdot E(Y)\)。定义 \(X\) 为经过这个点的次数,\(Y\) 为每次爆炸次数(显然同样取值 \({0,1}\)),则所求即 \(E(XY)=E(X)\cdot E(Y)\)。
同样,由 \(Y\) 取值 \({0,1}\) 知,\(E(Y)\) 数值上等于每次爆炸概率,即 \(\frac{p}{q}\) 。
所以,在一个点爆炸的概率,数值上等于在这个点的期望爆炸次数 \(E(XY)\),数值上等于这个点的期望经过次数 \(EX\) 乘每次爆炸概率 \(\frac{p}{q}\)。
求出到达一个点的期望次数是 trivial 的。
P2144 [FJOI2007] 轮状病毒
用 Matrix-Tree 定理当然非常正确,然而你发现直接做精度特别麻烦,要手写小数除法,恶心至极。
有人选择了使用蟒蛇 3,但是 FJOI2007 不能交蟒蛇 3,但是可以交用蟒蛇 3 打的表,所以蟒蛇启动。
有人观察 Kirchhoff 矩阵,用行列式结论得出递推式。很遗憾跨度太大结论太高深我看不懂,而且我本来也不懂 Matrix-Tree 定理。
你发现如果 Matrix-Tree 定理有模数就好办很多,所以你考虑来一堆互质的小模数,然后用 CRT 还原。
考虑我们取了 \(k\) 个质数,拿到 Matrix-Tree 定理在 \(m_i\) 意义下计算出来的所有答案 \(a_i\)。然后使用 CRT:
根据 CRT,我们有 \(M=\prod\limits_{i=1}^k m_k,M_i=\frac{M}{m_i}\),求出 \(M_i\) 在模 \(m_i\) 意义下的逆元 \(t_i\),答案就是:
我们发现这个过程要写高精度取模、高精度乘法、高精度加法,这太恶心了!我们考虑怎么不写这些东西。
使用蟒蛇 3。
发现 \(a_i\) 是低精的,\(M_i\) 只要每次 \(\mathcal O(n)\) 算一下对 \(m_i\) 实时取模再去算 \(t_i\) 就是低精的。这唯一需要高精的东西是 \(M_i\),与这俩玩意做乘法的时候进行一个高精乘低精就行了。但是还有个问题就是 \(\bmod M\) 咋搞呢???
你发现有一个美好的性质是 \(m_i\times M_i\equiv 0\pmod M\),这意味着,如果我们把 \(a_i\times t_i\) 对 \(m_i\) 取模之后再乘上 \(M_i\),对整体模 \(M\) 的结果毫无影响!所以,你可以先把 \(a_i\times t_i\) 取模,这样就是一个 \(<m_i\) 的数,乘上 \(M_i\) 之后也 \(<M\)。从而和式中的每一项都 \(<M\),那么就可以通过判断大小,每次减掉一个 \(M\) 实现取模完事啦。
P5192 【模板】有源汇上下界最大流
复健网络流,怎么会是呢?
首先考虑建模。
先来一个超级源点 \(S\) 和超级汇点 \(T\),然后给每位少女开一个点 \(P_i\),每一天开一个点 \(Q_i\),然后一步一步考虑限制:
- 每位少女 \(x\) 都需要被拍至少 \(G_x\) 张照片,所以 \(Q_x\to T\) 连一条要求流量为 \([G_x,\infty)\) 的边。
- 第 \(k\) 天的取材对象 \(C_{k,i}\),需要被拍 \([L_{k,i},R_{k,i}]\) 张照片,所以 \(P_k\to C_{k,i}\) 连一条要求流量为 \([L_{k,i},R_{k,i}]\) 的边。
- 第 \(i\) 天的拍照数量不能超过 \(D_i\) 张,所以 \(S\to P_i\) 连一条要求流量为 \([0,D_i]\) 的边。
求一个最大流。
我们发现这是一个有源汇上下界最大流,怎么做呢?
link:https://www.cnblogs.com/lemonniforever/p/18009379/lh-loves-wly
P4528 [CTSC2008] 图腾
会不了一点。后面的容斥还挺厉害的,自己推了一点和题解不一样的。
看了题解可以得知,我们可以利用离散化的思想,我们显然可以把一种形式抽象为 \(a,b,c,d\) 四个位置的排名,以最小的为第一名,那么闪电就是 \(1324\) 型,两种山峰分别是 \(1243\) 型和 \(1432\) 型。
那么答案就是 \(n(1324)-n(1243)-n(1432)\)。属实抽象,你根本不知道有什么用。
考虑补集转化,我们的目标肯定是把项消掉,或者起码要搞成加法吧。为了不生出来一大堆项,我们可以只把一种类型的两个位置给确定下来,这样就是一种空两位的形式减掉一种固定的形式。
比如 \(n(1324)=n(13??)-n(1342)\)。
随便往回看一下就能发现 \(1342\) 和 \(1243\) 简直是一个东西,于是把 \(n(1243)\) 改成 \(n(1?4?)-n(1342)\)。
代回可得答案变成了 \(n(13??)-n(1?4?)-n(1432)\)。
你发现 \(n(1432)\) 你也不会算,咋办呢?
看了题解可以得知,\(n(1432)=n(1?3?)-n(1234)\),\(n(1234)\) 肯定比这个好算多了。
代回可得答案变成了 \(n(13??)-n(1?4?)-n(1?3?)+n(1234)\)。
试了试发现 \(n(1?4?),n(1?3?)\) 似乎也不好算,因为需要关注他们两个中间和两边还要有数能插进去满足排名。
合在一起,\(n(1?4?)+n(1?3?)=n(1???)-n(1?2?)\),注意这里因为是排列所以不可能出现 \(1?1?\) 的情况,得到答案变为 \(n(13??)+n(1?2?)+n(1234)-n(1???)\)。
好像真的没什么可以瞪出来的巧合了,这个东西应该要可以算才对。
为了方便,我们让 \(L_i=\sum\limits_{j<i}[y_j>y_i],R_i=\sum\limits_{j>i}[y_j>y_i]\)。树状数组取得是 naive 的。
那么左边比 \(y_i\) 小的数的个数就应该是 \(i-1-L_i\),右边比 \(y_i\) 小的数的个数就应该是 \(n-i-R_i\)。
\(n(1???)\)
枚举 \(1\),答案直接 \({R_i}\choose{3}\) 完事了。
\(n(1234)\)
枚举 \(2,3\) 的位置 \(i,j\),再交换一下求和顺序,答案就是 \(\sum\limits_{j=1}^n\sum\limits_{i=1}^{j-1}(i-1-L_i)R_j=\sum\limits_{j=1}^n R_j\sum\limits_{i=1}^{j-1}(i-1-L_i)\),显然给里面那个求和做个前缀和就完了。
\(n(13??)\)
枚举 \(3\) 的位置 \(i\),那么左边的选法就是 \(i-1-L_i\) 种,右边的选法和 \(1\) 挂钩,这不好搞。
发现 \(4\) 有 \(R_i\) 种选法,其他位置的选法就是 \(j<i<k,y_i>y_k>y_j\) 的总方案数。
容斥,如果只管 \(y_j<y_i\land y_k<y_i,j<i\),那么有 \((i-1-L_i)(y_i-1)\) 种方案,需要减掉 \(k< i\land y_j<y_k\) 和 \(y_j\geqslant y_k\) 的部分。
对于 \(k< i\land y_j<y_k\) 的部分的方案数,显然应该是 \({i-1-L_i}\choose{2}\)。
对于 \(y_j\geqslant y_k\) 的部分的方案数,可以写成 \(\sum\limits_{j=1}^{i-1}[y_j<y_i]y_j\),这可以进行一次树状数组取得。
\(n(1?2?)\)
枚举 \(2\) 的位置 \(i\),那么右边的选法就是 \(R_i\) 种,左边的选法就是 \(j<k<i,y_k>y_i>y_j\) 的总方案数。
容斥,如果只管 \(y_i>y_j\) 那么就有 \((i-1-L_i)(i-1)\) 种选法,多算了 \(j<k,y_k<y_i\) 和 \(k\leqslant j\) 的部分。
\(k\leqslant j\) 的部分的方案数,可以写成 \(\sum\limits_{j=1}^{i-1}[y_j<y_i]j\),这可以进行一次树状数组取得。
\(j<k,y_k<y_i\) 的部分的方案数,显然应该是 \({i-1-L_i}\choose{2}\)。
于是这部分就做完了。
这些部分拼在一起就万事大吉了。
P4219 [BJOI2014] 大融合
好题啊,虽然 LCT 做法显然。能不能把 LCT 卡掉啊
LCT 做法:
加边直接加,查询的时候把点 \(x\) 转到根上,查询 \((siz_x-siz_y)\times siz_y\) 就完事了。
树剖做法:
考虑把所有边全部先加上,维护树上连通块并查集。
为了方便,每次把较深的连通块合并到较浅的连通块上。即使 \(dep_u<dep_v\)。
为了动态维护 \(siz\),每次把 \(v\) 合并到 \(u\) 上都需要将 \(u\to \text{find}(u)\) 的路径上的每一个点的 \(siz\) 都加上 \(siz(v)\)。显然 \(v\) 应该是它所在连通块的根,不需要套一个 \(\text{find}\)。
询问的答案就是 \((siz_{\text{find}(x)}-siz_{y})\times siz_y\)。
树剖并树状数组即可。
P8512 [Ynoi Easy Round 2021] TEST_152
回来两天硬是一道题都没自己做出来。
首先区间覆盖应当使用珂朵莉树。
首先有一个简单的想法:扫一遍操作,求出 \(r\) 处整个序列的和,再减去 \(l-1\) 处整个序列的和。但是会又涌现一个问题:\(l-1\) 处有很多位置原本就是有值的,如果 \(l\sim r\) 当中覆盖了这些位置,这些位置应该当成 \(0\) 来减。
我们发现问题出在统计到了区间外的贡献,所以我们应该离线,然后把所有询问按 \(r\) 从小到大排序,对询问从左到右地进行扫描线。当某个连续段加入的时候直接把 \((r-l+1)\times val\) 放在时间轴的当前时间 \(t\) 上,之后如果被覆盖,就在原处 \(t\) 上减掉被覆盖部分的长度 \(\times val\)。
那么当到达一个位置的时候就直接在时间轴上取 \([l,r]\) 上所有值的和就行了。
树状数组即可。
好像很自然,没关系,不妨碍我一直以来是傻逼,不会做一点紫题。
P7215 [JOISC2020] 首都
首先要求的意思就是要你找出一个连通块,满足这个连通块里面的颜色在连通块外不存在,并且这个连通块包含的颜色数量最少。
先想个暴力:枚举树根,钦定树根的颜色作最终连通块,把这种颜色的所有点都加进“有必要走到的点”的集合,然后向下走,遇到一种新颜色就把所有这种颜色的点都加进“有必要走到的点”的集合,走过一个点就把它从集合里删掉,直到集合空。
我们发现这不好做,因为不知道下面还有没有有必要走到的点,所以考虑反着来。以队列的形式维护“有必要走到的点”的集合,但是这次向上走(当然,如果上面那个点已经到过了就不用走了)。遇到一种新颜色就把所有这种颜色的点都加进队列(当然没遇到就什么都不做),并打标记再弹走刚刚离开的那个点。注意特判一下根要直接打标记弹走。等到队列为空的时候所有用到的颜色就是答案。
加上前面枚举根就是 \(\mathcal O(n^2)\) 的,喜提 \(11\) 分。这个暴力都难死了谁会去想啊
进一步考虑,有一个显然的结论,假设在颜色 \(x\) 作最终连通块的时候涉及到 \(y\) 颜色的连通块,那么 \(y\) 颜色作最终连通块的时候,答案也会涉及到 \(x\) 颜色,显然这是不优的。
所以这样我们就能考虑点分治了。每次把分治中心当成根做一遍 \(\mathcal O(n)\),当然那种有点在分治树以外的就不用管了。然后切树,继续往下做就没问题!
事实证明我根本不会点分治。