题5

模拟赛的题(不知道还能不能打开)

大意:给定一个排列,支持的操作是选定一个区间\([l,r]\)把其挪到最前面或最后面,定义\(f_{i}\)表示将这个排列变成没有\(i\)组成的逆序对的排列所需要的最少的操作次数。询问\(\sum_{i=1}^{n}f_i\le m\)的长度为\(n\)的排列数。

首先考虑\(f_{i}\)如何求。我们把大于\(i\)的设为\(1\),小于\(i\)的设为\(-1\),那么相当于操作需要把\(1\)都挪到右边,\(-1\)挪到左边。考虑一个操作\([l,r]\)如果包含\(i\),那么这个操作其实可以由\([1,l-1]\)\([r+1,n]\)替代。因为我们只关心\(1,-1\)\(i\)的关系。那么我们就把操作都变成了与\(i\)无交的操作了。那么此时答案其实就是\(i\)左边\(1\)组成的连续段个数,和\(i\)右边\(-1\)组成的连续段个数了。那么我们令\(p_0=-1,p_{n+1}=1\),那么我们要对\([-1,1]\)这样的东西进行计数,由于我们要求\(\sum\),所以考虑拆贡献。考虑一个\(i\)位置,什么时候\(i=-1,i+1=1\),即当枚举的\(x\in(p_i,p_{i+1})\)。所以这个位置对答案的贡献就是\(\max(p_{i+1}-p_i-1,0)\),对于\(p_0,p_{n+1}\)呢?将\(p_{0}=0,p_{n+1}=n+1\)即可。那么我们就是对\(\sum_{i=0}^{n}\max(a_{i+1}-a_i-1,0)\le m\)这样的排列进行计数。那么就是连续段\(dp\)进行解决了。

模拟赛

大意:\(n\)个在\([1,m]\)中均匀随机的数组成的\(a\)序列,求出其众数出现的次数的期望

定义\(f_i\)\(i\)在序列\(a\)中出现的次数,那么众数的次数就是\(\max_i f_i\)。我们考虑\(Min-max\)容斥(想到的是神人)。对\(f_i\)进行容斥。由于\(f_{i}\)的下标的值,所以全集就是\(U={1,2,\dots,m}\)\(\max_i f_i=\sum_{S\subseteq U}(-1)^{|S|+1}\min_{j\in S}f_j\)。我们是不关心具体的值的,我们只关心\(|S|\)也就是出现的不同数的种类。设出现了\(k\)个数,每个数出现的次数为\(a_i\)那么就可以变成\(\sum_{k=1}^{n}(-1)^{k+1}A(m,k)\frac{n!}{\prod a_i!}\min_j f_j\)。然后我们考虑求出\(\frac{n!}{\prod a_i!}\min_j f_j\)。由于直接等于太困难,我们先求出\(\min\ge k\)的值,然后差分。使用\(dp\)求解。我们从大到小放出现的次数\(a\),设\(f_{k,i,j}\)表示放了次数\(\ge k\)的数,出现了\(i\)种不同的数,一共放了\(j\)个数的方案。然后转移就转。是\(O(n^3)\)的,然后常数比较小,就过了(狗头)

补:其实根本不用容斥的,我们直接求\(A(m,k)\frac{n!}{\prod a_i!}\max a_i\)。然后还是从大到小放数,那么我们放的第一个就是\(\max\)。所以我们只需要在\(i\)\(0\to >1\)的时候把\(a\)的贡献加上就行,转移一样,最后就不用差分了。想题的时候一定要想简单一点。(用容斥反倒复杂了)

QOJ6669

拉插,然后存一下系数。\(nb\)题目。

总结:把两个值压缩成一个值可以通过拉插然后记录系数。还需要知道次数。

插播一下拉插:给定\(n\)个点\((x_i,y_i)\),确定一个\(n-1\)次多项式,式子就是\(f(x)=\sum_{i}^{n}y_i\prod_{j\ne i}\frac{x-x_j}{x_i-x_j}\)。正确性就是带入一个\(x_p\),当\(i=p\)时,后面的连乘等于\(1\),否则会出现\(x_i-x_i\)而导致连乘变成\(0\)。然后写的话就是多项式乘法和多项式除法做到\(O(n^2)\)

P9523 [JOIST 2022] 复制粘贴 3 / Copy and Paste 3

考虑答案是怎样构成的。一开始想的是先处理一段后缀,然后粘贴到\(Y\),然后在放一段前缀,然后把\(Y\)放到后面,但是这样不对。因为只是用了一次粘贴,这样肯定不是最优的。考虑如何使用多次。如果\(S\)中有一个串\(x\)出现了多次,那么我们可以先造出来\(x\),然后在粘贴,然后把不是\(x\)的用操作一,碰到\(x\)用操作三。我们发现这样就覆盖了所有可能的策略。考虑实现。设\(f_{i,j}\)表示拼出串\(S_{i\sim j}\)需要的最小操作次数。首先,基本的,我们可以由\(f_{i+1,j}+A,f_{i,j-1}+A\)转移过来。接着我们考虑,不是这两种操作的还有什么。即一开始就用粘贴操作。也就是存在一个\(x\)即使\(x\)的前缀,也是\(x\)的后缀。那么我们枚举一个\(S_{i,k}\),满足这个也是\(S_{i,j}\)的后缀,然后计算中间有多少个不重叠的\(x\)。然后计算贡献。实际实现的时候,我们枚举\(l,i\),然后枚举下一个\(S_{l,i}\)出现的位置,在位置的末尾\(r\)处更新\(f_{l,r}\)。考虑,复杂度最爆炸的时候就是全\(a\)的时候,此时考虑每个点作为结束节点的次数,就是\(\sum_{len}^{n}{\frac{n}{len}}\),那么就是\(O(n^2\log n)\)。而找下一个出现次数的可以做到\(O(n^2)\)

总结:考虑答案是怎样的形态,抽离出可以包含所有情况的模型,然后通过这个进行转移。

P7620 CF1431J Zero-XOR Array

这个题很厉害!主要思想就是找到在所有数中,第一个出现的不压上界和不压下界的位置,注意我们找的是所有数中的,加入有两个数\(a_i,a_j\),他们第一个不压上下界的位置是\(k_i,k_j\),我们看的是\(k_i,k_j\)的大小而不是\(i,j\)的大小。这点很重要。如果出现了,一个最早的位置\(k\)不压上下界,根据定义,所有数的所有前\(k-1\)位都是压着上界或下界的。而对于其他数,我们设他确定了第\(k\)位即以前的数后后面的位置还有多少选择\(x_i\)。那么答案就是其他数的\(x_i\)乘起来。因为由于当前数已经不压上下界了,所以相当于后面的位置可以随意的选择,所以无论其他的怎么变都可以使得答案为\(0\)。到这里,题目基本解决了。实现上,我们考虑枚举第一个出现的位置,那么前面的位置不是压上界就是压下界,总共会有\(2^{n-1}\)种情况,我们先判断这些情况是否是合法即能不能让前\(k\)位异或和为\(0\)。如果合法,我们对第\(k\)位每个数是\(0\)还是\(1\)进行\(dp\)。就是说,我们设\(f_{0/1,0/1}\)表示现在到当前这一位的异或和位\(0/1\),是否出现过了不压上下界的点的总方案数。然后转移需要分讨,比较麻烦,需要在脑子清醒的时候写。但是是一道好题!!

总结:在数位\(dp\)过程中,如果出现了一个不压上下界的位置,那么后面的位置都可以随便填了,这个性质很重要!!。在二进制中,一个可以随便填的数就能操控最终的异或和了。

P6097 【模板】子集卷积

考虑\(i\cap j=0\)的限制怎么翻译。就是\(|i|+|j|=|i\cup j|\)。那么我们设\(F_{i,j}=|j|==i?f_j:0\)。那么我们枚举\(popcount\),然后把他拆成两个相加,具体的就是\(C_{i,j}=\sum_{i_1+i_2=i}\sum_{a|b=j}FA_{i_1,a}\times FB_{i_2,b}\)。可以看到,后面的内一项就是\(FA_{i_1}\oplus FB_{i_2}\),就是或卷积。或卷积完了后我们需要把\(C\)\(|j|\ne i\)的位置赋为\(0\),就是不合法。这样我们就得到了\(O(2^nn^2)\)的做法。

总结:\(i\cap j=0\)可以翻译成\(|i|+|j|=|i\cup j|\)

sez885

咋说呢,感觉脑子成屎了还想用\(bitset\)。。就是枚举一个\(ans\),大于等于他的是\(1\),其余为\(0\),然后维护一个数组\(b[i][j]\)表示\(i,j\)都是\(1\)的在前面行有没有出现过。看起来挺爆的,但是每个二元组只会被放一次,所以只有\(n^2\)次操作,所以复杂度就对了。

总结:对于一些有两个就行的东西,每一个只会被扫到一边,所以复杂度应当算每个只扫一遍的。。

P5356 [Ynoi Easy Round 2017] 由乃打扑克

这个看了些提示,感觉分块太不熟练了。
就是分块,对每一个块维护从小到大排序后的数组,还有\(lazy_tag\)。对整块加不影响大小关系所以直接加到\(tag\)上,散块上暴力重构。修改操作就这样。查询比较重要应该感觉忘了。因为要查询排名是第\(k\)的数,一般有两个,一个是维护至于选段书然后线段树二分,另一个是二分枚举一个值找数组里有多少小于和小于等于他的数。由于这个题是区间查询区间修改所以第一种方法就不行了。所以采用第二种,对于散块就暴力找,整块上就使用排序后的数组去找。然后就没了。复杂度\(O(m\sqrt{n}\log V\log n)\)卡常。

卡常技巧:\(lower_bound\)时,特判一下和第一个和最后一个的大小关系。\(upper_bound\)也是。

总结:查询第\(k\)小的时候:1. 维护值域线段树进行线段树二分。2. 二分一个数寻找有多少个比它小的数,为了寻找这个并且避开权值线段树,采用将数组分段排序的做法。

P3863 序列

这个思路还没见过。首先我们可以把每个查询的位置\(y-a_p\),这样就相当于所有的\(a\)初始为\(0\),这个很重要,因为这样就保证了,所有\(a\)的初始状态相同。我们考虑这个时间维的问题,他对时间大于的操作都会有影响,也就是对一个时间后缀进行操作。对于一个修改操作\([l,r]\),我们可以把它拆成两个操作\([l,n],[r+1,n]\)。所以现在我们只需要对后缀进行操作了。我们考虑如果有一个横轴是时间,纵轴是那个数组的矩阵,\((t,i)\)表示时间\(t\)\(a_i\)的值是什么。那么修改就是对一个右上角的矩形进行统一改。维护矩阵的信息我们就尝试使用扫描线。那么查询呢,\(t\)时刻的查询\(i,x\)就是找\(a_i\)内一行前\(t\)个中大于等于\(x\)的个数。所以我们需要知道横行的消息。所以我们需要维护时间轴,所以我们就在序列轴进行扫描线。具体的,我们在每个位置挂上询问和修改,修改的话,由于要维护比\(x\)小的值,所以我们借用上一个题的思路,就做完了。

总结:有关时间的序列操作问题,可以画出时间-元素图,查看是否能够转化成对一个矩阵进行操作,如果可以,尝试使用扫描线,扫哪一维需要根据查询的类型确定,比如这个,我们维护不了矩形中小于等于\(x\)的个数,但是能维护一个序列,所以以元素为扫描线。

P5268 [SNOI2017] 一个简单的询问

把答案差分一下就行了。\((get(1,r1)-get(1,l1-1))*(get(1,r2)-get(1,l2-1))\)然后拆成四个,这样就直接用莫队维护了。

P4689 [Ynoi Easy Round 2016] 这是我自己的发明

上面内阁题的强化版,就是把树转到\(dfn\)做,然后根的问题就使用两个树相减就行了。

注意:如果用\(Ans_i=-1\)来标记这个是否是查询操作,这样是不太对的,因为第二个题会有预处理的部分,所以可能恰好变成\(-1\),这样就错了。喜提调一晚上。\(GPT\)牛逼。

P4590 [TJOI2018] 游园会

\(dp of dp\) 的板子。设奖章串为\(A\),我们首先考虑兑奖串\(B\)确定时如何求最长序列,\(f_{i,j}\)表示\(A,B\)分别匹配到\(i,j\)时的最长子序列,\(f_{i,j}=\max(f_{i-1,j},f_{i,j-1},f_{i-1,j-1}+[A_i==B_j])\)。现在\(B\)是随机的,先不考虑\(NOI\)的限制。根据上面的式子,我们发现,我们想要求出\(j+1\)的所有数组,我们只需要知道\(f_{1\sim k, j}\)即可。于是我们考虑把这个东西放到状态里,设\(g_{i,S}\)表示枚举到第\(i\)位的时候,\(f_{1\sim k, i}\)压成了\(S\)时的方案数是多少。那么转移就好转移了,就是转移中套一个转移。但是我们发现压的时候很难受,太大了。接下来到了这个题关键的时候,就是如何压。针对最大子序列下手。有两个性质:1. 递增2. 相邻两个至多差\(1\)。于是我们可以直接记差值。也就变成了\(2^k\)个状态可以接受。至于\(NOI\)的限制,多加两维限制一下就行。

总结:若要压一个序列,考虑这个序列是否是特殊的,如单调,相邻两个差值很小,个数比较少。

P10107 [GDKOI2023 提高组] 树

确实是好题。
如果是一个\((i,i+1)\)这样的一条链,可以倍增(想到是不可能想到的)。就是维护\(f_{i,j}\)表示\([i,i+2^j-1]\)部分的答案是多少。合并\([i,i+2^{j-1}-1],[i+2^{j-1},i+2^{j}-1]\)。考虑,\(f_{i,j-1}\)的答案是对的,直接加就行了。但是后面呢?关注贡献形式,相当于是\(v\oplus (dis+2^{j-1})\)。问题在于\(2^{j-1}\)怎么办,因为如果进位的话会很麻烦。但是我们考虑,\(dis\)不可能\(\ge 2^{j-1}\),因为是在\([i+2^{j-1},i+2^{j}-1]\)区间内与\(i+2^{j-1}\)的距离。所以加\(2^{j-1}\)想到与\(\oplus 2^{j-1}\)。那就好办了啊,我们差分一下维护\(l,r\)区间内第\(j\)位为\(0,1\)的个数就能做了。怎么转到树上,使用长链剖分优化一下,复杂度\(O(n\log n)\)

注意:转到树上的时候,我们维护\(g_{i}\)表示从\(i\)到其所在长链末尾的\(0/1\)个数,如果维护到根的,那么我们维护正确的信息复杂度就错了。而这样维护可以通过类似懒标记的方法把修改传递上去。

总结:1. 树可以先转到链上做。2. 加一个\(2^{j}\)有时可以变成$\oplus $。3. 差分既可以维护前缀也可以维护后缀。

sez893

这个,分块做法比较好想,就是块的大小为\(B\),维护当前块内的回文串数量和被什么所覆盖,然后就暴力,边界也暴力。使用马拉车判回文这样,取块为\(\sqrt{mk}\),卡飞了。优化是因为覆盖一个区间,所以是用线段树维护,线段树的节点是每个块的编号,然后复杂度就是 \(\log{\frac{n}{B}}k\),应该可以过(代码先咕一咕)。。

sez888

这个挺神的。就是把序列按照\(k-1\)分块,这样每一个查询系列就能恰好被分成一个块的前缀和一个快的后缀。这些是好维护的。好题。

总结:若询问区间长度固定,则可以分块把询问区间分成两个前缀和后缀

P6189 [NOI Online #1 入门组] 跑步

这个算是个典题把,就是小于\(\sqrt{n}\)的数用完全背包做,\(>\sqrt{n}\)的数一定不会出现\(>\sqrt{n}\)次,所以就\(f_{i,j}\)表示用\(j\)个数表示出\(i\)的方案数,\(f_{i,j}\to f_{i+\sqrt{n}+1,j+1},f_{i,j}\to f_{i+j,j}\)。分别对应着新加一个数,和全局加\(1\)。时间复杂度\(n\sqrt{n}\)

P8340 [AHOI2022] 山河重整

这个感觉好困难啊。。。

先介绍一个数划分的方法。当每个数只能使用一次的时候,我们有性质是最多只会出现\(\sqrt{n}\)个数。所以我们换一种枚举方式。就是我们把最后的集合的数从小到大排序,然后每一行每一行加。就是我们把值看作下标,把小标看着值。例如\(4,3,1\),变成\(3,2,2,1\)。这样。我们相当于有了\(1\sim \sqrt{n}\)这些物品,然后\(i\)出现则\(1\sim i-1\)都要出现,做完全背包。所以我们只需要从大到小枚举物品,枚举到一个物品先给前面的所有方案都加上该物品,在用这个物品跑完全背包。

首先看原题意的充要条件:\(\forall k\in [1,n],\sum_{x\le k,x\in S}\ge k\)。易证,考虑\(dp\)过程即可。然后考虑容斥掉不合法的情况。我们在第一个不合法的位置进行容斥,由于是第一个不合法的,即第一个满足\(\sum_{x\le k}<k\),所以\(\sum_{x\le k-1, x\in S}=k-1,k\notin S\)。这个是个很好的性质。但是容斥系数怎么去。我们想要枚举第一个不合法的位置,就要求前面都合法并且\(1\sim i\)中的数和恰好为\(i\)。所以我们设\(f_{i}\)表示\(1\sim i\)中有多少子集使得\(1\sim i\)都合法并且子集和为\(i\)。那么答案就是\(2^n-\sum_{i=0}^{n-1}f_{i}\times 2^{n-i-1}\)。问题转化为怎么求\(f_{i}\)。我们已经考虑容斥,总方案就是\(1\sim i\)表示出来为\(i\)的方案数设为\(h_i\)。这个是划分数。但是这个题中每个数只能用一次,所以我们在这里使用一个其他的办法,和正解相关。就是上面提到的数的划分方法。继续往下考虑。得到式子\(f_{i}=h_i-\sum_{j=1}^{i}f_j\times h(j+2\sim i, i-j)\),其中\(h(j+2\sim i, i-j)\)表示用\(j+2\sim i\)中的数表示出\(i-j\)的方案数。我们考虑如何对每个\(i\)都求出\(g_i=\sum_{j=1}^{i}f_j\times h(j+2\sim i, i-j)\)。这个就涉及到刚刚的内阁数划分方法了。就是普通做数的划分,就是个数从小到大枚举。这个由于有限制的范围,所以我们可以在一开始加入物品的时候先把所有的就加上,例如,若一共有\(i\)个物品被加入,并且起点是\(j\),那么加入\(j+(j+2)*i+i\)。然后在做背包,相当于给每个方案加入了一个\(j+(j+2)*i\)的偏移量。然后贡献呢?数的划分,我们记录方案,所以贡献相当于是\(1\)。但是这里不是方案,二十值,所以贡献就变成了\(f_{j}\)。就是说,我会加入\(j+(j+2)*i+i,i\in [1,\sqrt{n}]\)这些物品,这些物品的初始权值都是\(f_j\),而能通过多少种方案到达\(k\)\(f_{j}\)就被加了多少次,所以就是\(g_k\)了。所以这样就是对的。但是复杂度还是\(O(n^2)\)的。咋办。此时我们关注到当\(j+2\sim i\)能拼出来\(i\),说明\(j+j+2\le i\),所以我们要求\(i\),只需要知道\(1\sim \frac{i}{2}\)就行了。所以我们可以直接分治做。就是先求出\(1\sim 2^x\),再求出\(2^x+1,2^{x+1}\)。那么\(n\sqrt{n}\)就这样了。

总结:当数只能用一次时,最多会出现\(\sqrt{n}\)个数,这是我们把行和列换一下就能做到\(n\sqrt{n}\)了。在这种方法中,我们可以灵活的改变起点,只要区分出来权值就行了。好题

注意:这样的数的划分,最大值取\(\sqrt{n*2}\),因为\(x(x+1)=2n\),所以\(x\)\(\sqrt{2*n}\)不能取更小的。

Loj6515. 「雅礼集训 2018 Day10」贪玩蓝月

这个比较有意思。他不允许我们撤销了。但是\(p\)很小。有操作和删除操作,所以我们能得到每个数处在的时间范围是什么,那么我们建线段树节点时时间点,然后把每个数存在的时间上打上\(tag\),然后类似缺一分治内样,从根节点到叶子节点,如果有点就加上,单次加复杂度是\(p\)的,每个数最多被加\(\log n\)次,复杂度是\(np\log n\)的。比较巧妙。

总结:遇到加入和删除操作,可以利用时间轴,表示每个数出现的时间范围是什么,在时间轴上做。如果可撤销就直接撤销就行。

P6326 Shopping

树形背包+点分治树形背包+二进制分组背包。感觉很好的一道题啊。

我们先来介绍一种不一样的根联通树形背包的做法。先跑出\(dfs\)序。由于\(dfs\)序保证了子树里面编号是连续的。我们设\(f_{i,j}\)表示考虑了\(dfs\)序为\(i\sim n\)的点,背包和为\(j\)获得的最大收益。有一个\(i\),不选\(i\),那么\(i\)子树里都不能选,所以由\(f_{i+sz_{seg_i}}\)复制过来。如果选,那么我们从\(f_{i+1}\)\(i\)做一个背包就行了。考虑\(i+1\)不是到他的儿子,就是他是叶子到了下一个子树的根节点,转移都是合法的。而这个复杂度的,因为我们只需要求\(rt\)的值,所以复杂度就是\(O(nm)\)的。有点好看的做法。\(dfs\)从前往后也可以,从填表转成刷表就行了。

然后再介绍一下多重背包的优化,二进制分组。我们把每个物品的数量\(d\)拆成\(1,2,4,8,\cdots,2^{k-1},d-(2^k-1)\)。这样\(1\sim k\)中每个数都能被\(0/1\)表示。所以现在变成了\(\log n\)个物品,所以复杂度就是\(O(n\log dm)\)也很好啊。还有一种做法是单调队列优化,就是按照\(%m\)进行分类,每个都开一个单调队列。转移就\(O(1)\)这个复杂度就变成了\(O(nm)\)不过上面内阁就挺优的。

再说这道题。经典的\(trick\)是进行点分治,我们再每个连通块第一个作为分治中心的点出进行求解,就是用上述两个办法。然后就做完了。

总结:板子,进阶例题qoj4815,不过这个也有其他更优做法。

注意:由于\(f_{i+1}\to f_{i}\)的时候,强制\(i\)选了,所以转移的时候先强制都选一个,二进制分组的时候分\(d-1\)就行。复杂度不变。

qoj4815

来说一下这个,这个就是上面内阁dp方式有大用的题目。因为这道题要求的是每个\(x\)所在的连通块的最大权值。我们还是再每个连通块最先成为分治中心的点处统计。但是怎么解决找每个点呢。接下来我们定义左边的树是相对的,就是\(u\)左边的点就是比他先遍历到的点并且不是他祖先的点,右边的是比他后遍历到的点。那么我们考虑,一个点所在的连通块在当前的分治根为\(rt\)的部分怎么表示。可以拆成\(3\)部分。\(u\to rt\)\(u\)左边点,\(u\)右边的点。我们考虑,\(u\)右面的点的\(dfs\)序是一段后缀对吧,这就很好,因为我们的\(dp\)是从后往前的。但是左边的树呢?他不是连续的,会断。不过没关系,我们倒着\(dfs\)一遍就行了,就是先遍历\(u\)的最后一个儿子。这样的到了两个\(dp\)数组。我们只需要在\(x\)处,挑出两个后缀,加上\(u\to rt\),然后使用\(O(k)\)的时间复杂度找到和为\(k\)权值最大的方案。

总结:\(u\)所在连通块可以分成\(3\)个部分,\(u\to rt\)\(u\)左边的树,\(u\)右边的树。

P9197 [JOI Open 2016] 摩天大楼 / Skyscraper

这个是连续段\(dp\)的板子。思路和一般的连续段\(dp\)差不多,需要分讨

P2522 [HAOI2011] Problem b

莫比乌斯反演和二维整除分块,\(O(n\sqrt{n})\)

总结:莫比乌斯反演;二维整除分块

Loj6077

这个妙妙题。这个第一步可以想到就是,考虑每个位置能产生的贡献其实与其前面的无关,只和其位置有关。第\(k\)个位置能产生\(0,\dots,k-1\)。所以可以写成一个多项式\(1\times (1+x)\times (1+x+x^2)\times\dots\times(1+x+\dots+x^{n-1})\)。那就可以写成\(\frac{\prod_{i=1}^{n}(1-x^i)}{(1-x)^n}\)。我们先看下面这个,因为有分式所以很烦啊。但是\(\frac{1}{1-x}\)\(\sum_{i=0}x_i\)的封闭形式,然后这两个就是等价的,证明不会。那么下面内阁第\(k\)项的系数就好说了啊,相当于把\(k\)分成\(n\)\(\ge 0\)的整数。然后这个插板法就做了。然后上面内阁怎么算。其实我们可以看作有\(1\sim n\)个数,问拼出来\(1\sim k\)之中的数的方案数,数不重复。我们先考虑一下如果\(k\le n\)时。如果有重复那么就直接数的拆分做。没有重复带来一个性质是一定不会有\(>\sqrt{n}\)个数。回想一下数的拆分的算法流程。给全集加\(1\),新加一个\(1\)。没有重复的数的性质等价于没有两个连续的操作是新加一个\(1\),换句话说就是新加一个\(1\)后一定跟着给全集加\(1\)(末尾操作除外)。那么我们直接强制做这个操作就行了。统计答案的时候加上末尾是\(1\)的贡献就行了。如果\(k>n\)的时候呢?直接做可能会有\(>n\)的数放到方案里,我们需要剪掉这种方案。观察上面的两个操作,最多会给最大值加\(1\),所以第一个不合法的时候最大值是\(n+1\)(废话)。并且只有一个。设\(h_{i,j}\)表示用\(j\)个数拼成\(i\)的合法方案数。所以现在还没确定的方案只能由合法方案转移过来,所以不合法也是第一个不合法。所以只需要\(h_{i,j}-=h_{i-n-1,j-1}\)。注意:这个只需要减一次,所以在遍历到的时候写就行。
有点模板。

for(int j = 0; j <= B; j ++) {
        for(int i = 0; i <= k; i ++) {
            if(!h[i][j]) continue;
            if(i > n) h[i][j] = dec(h[i][j], h[i - n - 1][j - 1]);
            if(j) {
                h[i + j][j] = Add(h[i + j][j], h[i][j]);
            }
            h[i + j + 2][j + 1] = Add(h[i + j + 2][j + 1], h[i][j]);
        }
    }
f[0] = 1;
    for(int i = 1; i <= k; i ++) 
        for(int j = 1; j <= B; j ++) {
            int x = (j & 1) ? -1 : 1, y = (h[i][j] + h[i - 1][j - 1]) % mod;
            f[i] = Add(f[i], (x == -1) ? mod - y : y);
        }

CF1781F Bracket Insertion

计数好题。本质上还是计数啊。

括号问题一般会转成\(\pm 1\)做。这倒也是。但是这个题的操作没见过。不过转化一下能转化成挑一个位置设其前缀和为\(x\)把其后面加上\(x+1,x\)\(x-1,x\)问最后所有数非负的方案。所以问题就是原来集合\(S=\left\{ 0\right\}\),每次选择\(x\in S\),加入\(x+1,x\)\(x-1,x\)。问最后非负的方案数。但是接下来就没思路了。(观摩题解)根据这个转化题意我们能找到一个状态的设法\(f_{x,i}\)表示\(S\)初始是\(x\),进行\(i\)此操作后合法的方案数。答案就是\(f_{0,n}\),然后根据题除以总方案数。考虑怎么转移,我们考虑进行一次操作,由于第一次,所以只有两个选择。1. \(S\to \left\{ x_1,x+1,x_2\right\}\),此时我们把操作分为三类,由\(x_1,x+1,x_2\)分别拓展出来的。那么贡献为\(f_{x,n}=p\sum_{i=0}^{n-1}\sum_{j=0}^{n-1-i}f_{x,i}f_{x+1,j}f_{x,n-1-i-j}\times \binom{n-1}{i}\binom{n-1-i}{j},\)。2. \(S\to \left\{ x_1,x-1,x_2\right\}\),转移同理。此时我们得到一个\(O(n^4)\)的做法。调换一下枚举顺序,先枚举\(n-1-i-j\),然后再用前缀和优化一下就行了。好题;

总结:不知道怎么设状态的时候,可以尝试把问题转化一下,将起始状态或终止状态或中间状态放到状态里,(防止爆掉)也可以是转移过程(dp of dp);进行操作型的\(dp\)不知道该怎么转移的时候可以考虑先操作一步,得到新的状态后再做,就像期望的\(dp\)一样,从后往前进行\(dp\)

CF1305F Kuroni and the Punishment

--随机化题--

就是答案一定不超过\(n\),因为把每个数变成偶数就行。有这个性质推的,一定有一半以上数不变或加一或减一,否则不满足上述性质。那么我们随机一个数,不变加一减一,然后分解,找答案,对的概率是\(\frac{1}{2}\)。多随机几遍就行了。

。。。。

CF13C Sequence

这个有点神奇不过也挺有意思的。就是要关注到最后序列的数组成的集合一定是原来序列数组成的集合的子集。就是,考虑如果最后变成了一个数,那么通过调整法我们知道一定是变成原序列的一个数是最优的。然后如果变成了两个数,三个数就是归纳一下,但是有点感性不过写了确实对了。。。这个做法\(O(n^2)\)。还有更厉害的是下面的加强版。

P4597 序列 sequence

这个就是加强版。对于每一个\(j\),\(f_{i,j}\)\(i\)都是下凸的。这个使用\(slope trick\)。因为要维护前缀最小值,所以线段的斜率最多维护到\(0\)。然后我们维护斜率拐点的集合,就是一个点代表斜率\(+1\)例如,\(()1-2,-2),(2-3,0)\),那么在集合里加入两个\(2\)。然后这个题目实际上是若干个绝对值函数加起来\(\sum{|x-a_i|}\),所以加入一个\(|x-a_i|\)这样的函数,相当于加入两个拐点\(a_i\),因为绝对值函数在\(a_i\)处的斜率变化为\(2\),下凸函数是可叠加的(别的其实也能叠加)。由于我们维护的是下凸的函数的前缀\(\min\),所以我们不需要维护斜率大于\(0\)的线段。我们考虑,加入\(a_i\),在\(a_i\)右边的线段的斜率都\(+1\),所以最大的拐点右边的线段都从\(0\to 1\)了,所以我们需要把最后一个拐点删去,这样就行了。然后删和加的过程中,把斜率为\(0\)的线段左端点的答案维护一下。就能做了。

for(int i = 1; i <= n; i ++) {
        ll x;cin >> x;
        q.push(x);q.push(x);// 加入两个拐点
        ans += q.top() - x;// 这个是维护最小值现在的值,因为最大的拐点右边就是斜率为$0$的线段,所以给后面的加$1$后,这个点的左边就恰好是斜率为$0$的线段,也就是他恰好还是最小值。所以加上多余的贡献
        q.pop();// 由于这个点的左边恰好是斜率为$0$的线段,所以我们要找左边第一个左边不是斜率为$0$的线段的点,否则下次再$+1$他就不是最小值了,而是前面是最小值。
    }

总结:遇到多个凸函数相加的题目,能得到新函数还是凸函数,此时可以用\(slope trick\)优化复杂度。

CF713C Sonya and Problem Without a Legend

上面的经验,主要想说,让序列变成严格单增转成不严格单增的方法是先给\(a_i-i\)

P10013 [集训队互测 2023] Tree Topological Order Counting

这个感觉是一个比较传统的\(dp\),就是设\(f_{i,j}\)表示考虑了除了\(i\)的儿子的其他所有点,\(i\)排第\(j\)的方案数。从父亲节点转移到儿子。注意:这里的定义,是相当于把\(i\)的儿子都删掉,而不是预留出他的位置,第二种\(dp\)是错的(可是我推了两个小时)。初步转移能出来一个\(n^3\)的,然后观察一下能前缀和优化就变成\(n^2\)了(然鹅由于第一个的影响,我以为像第一个优化不了。。。)

总结:写状态的时候想好除了的含义是删掉做子问题还是预留出位置;前缀和优化\(dp\)比较常见,一般遇到需要一个前缀和的都要用前缀和优化。

sez596

这个主要有一个主要的性质没有关注到。就是\(a_1+a_2,a_1+a_3\)都是确定的,我们只需要知道\(a_2+a_3\)就能得到\(a_1\)了,然后就能在\(n^2\log n\)的复杂度内找出所有数。但是\(a_2+a_3\)直接枚举是\(V\)的。但是有一个性质就是\(a_2+a_3\)的排名在\(3\sim n+1\)内。所以只有\(O(n)\)个取值,也就只有\(O(n)\)\(a_1\)。那复杂度就是\(O(n^3\log n)\)了。

总结:减少\(check\)的次数,关键要找不同的取值次数。而找这个要结合已知信息,找需要什么未知信息,找未知信息的取值个数。(对于不确定的问题这类处理的还是不是很好啊)

sez918

期望题。首先这个在第几轮死可以看成有多少人死在\(1\)前面\(+1\)。而对于每一个\(i\)来说,死在\(1\)前面的概率就是\(\frac{w_i}{w_1+w_i}\)。为啥呢。因为考虑把\(1,i\)合成一个点,对于他们两个来说,\(i\)\(1\)前面的概率就是前面内个,而其他的点,他们死的顺序不会影响这个点,就是他们组成的事件集合发生的概率是\(1\),所以整体看就是前面提到的概率。而一个人在前面就产生\(1\)的贡献,所以答案就是\(1+\sum{p_i}\)\(p_i\)表示\(i\)死在\(1\)前面的概率。

总结:期望概率题做得太少。

sez600

这个题挺有意思的。就是换两个对序列产生的影响是奇偶性不变,那么必要条件就是逆序对数是偶数。考虑是否是充分条件,这就构造了,就是构造方案。考虑一个排列的情况,就是我们找到当前没有回到应在的位置的最小数,把他和他后面的内个数连在一块,放到最小数应在的位置(在最后的位置就先挪到前面,不能移到前面当且仅当是\(n,n-1\)这样的东西,但是这样就违背了前面的条件)。所以充分必要。然后考虑如果不是排列,有重复元素的话,我们把重复元素按照一定顺序标上大小关系就行了。此时一定可以通过改变重复元素的最后一个元素来改变逆序对的奇偶性,所以就一定是好的。所以不好的是逆序对为奇数的排列。然后考虑这个怎么求。啊这个就是技巧类的把就是(积和式-行列式)/2。由于这个矩阵有点特殊,每行恰好前\(i+1\)位有值,积和式可以\(dpO(n^2)\)求出。行列式可以让\(i=n-1\to 1\)\(i\)行-\(\frac{w_{i,i+1}}{w_{i+1,i+1}}\)倍的第\(i+1\)行,这样就能变成一个下三角矩阵,此时的行列式就是对角线乘积了。

总结:要对一个不确定的序列计数,我们可以先找到一个必要条件,然后证明他是充分的,或者直接在必要条件的情况下向下\(dp\),看这个情况下有多少合法的;每行只有前\(i+1\)有值的矩阵,行列式和积和式都能在\(O(n^2)\)中求出。

CF1810G The Maximum Prefix

这个题和下面内个题分别体现了两个经典好用的优化\(dp\)方式。有点像。先说这个。本来设\(f_{i,j}\)表示长度为\(i\)的前缀最大前缀和恰好在\(i\)处取到,为\(j\)的概率,但是转移是\(O(n^3)\)的并且无法优化。由于有前缀最大值,我们关注的是历史上出现的,所以我们可以钦定一个最大值,然后找是否经历过,钦定最大值是\(S\),设\(f_{i,j,0/1}\)表示当前\(i\)距离最大值为\(j\),是否经历过最大值的概率,转移是好说的,初始化就是\(f_{0,S,S==0}=h_S\)。其余都为\(0\)。最后输出\(f_{n,0,1}\)。但是要钦定,还是\(O(n^3)\)。不过,我们发现,对于不同的\(S\),除了初始化不同,转移方式完全相同啊。有这个,我们就能把他们放到一起转移,初始化就\(f_{0,j,j==0}=h_j\)。然后输出还是\(f_{n,0,1}\)

总结:遇到最大值,最小值,可以考虑钦定,如果是历史上的,就加是否遇到过;无后效性的\(dp\)可以看作一个\(DAG\),如果转移过程和起点无关,那么我们可以把所有起点都加进去一起\(dp\)能够降低复杂度;

CF2018F3 Speedbreaker Counting (Hard Version)

性质I:合法的起点一定是一个区间,这个好证。有了这个,我们钦定\(l,r\)是合法的,计算\(f_{l,r}\)表示钦定\(l,r\)为合法的区间的方案数,然后容斥\(ans_{l,r}=f_{l,r}-f_{l-1,r}-f{l,r+1}+f_{l-1,r+1}\)得恰好。然后考虑怎么判断一个\(a\)\(l,r\)是否合法。性质II:我们一定可以先走完\(l,r\)。就是考虑,没有走的内个点设为\(k\),必须在\(k\)之前到得点设为\(z\),当前起点为\(j\),那就是\(j\)走到\(z\)才能走到\(k\),那\(k\)当起点的时候就不能走到\(z\)了,所以不满足是一个起点。得证。那么我们考虑在这个性质下怎么走。设当前拓展的区间是\(i,j\),若右边有个\(k\)满足\(a_k=k-i+1\),那么必须往右走,否则向左走。那么移动顺序确定了。考虑计数。设当前钦定得合法区间是\(L,R\),设\(g_{l,r}\)表示从\(L,R\)走到\(l,r\)得填值方案数。首先\(L,R\)中的点的方案就是\(\prod{n-\max(i-L+1,R-i+1)+1}\)。考虑外面。由于要枚举\(k\),所以\(g_{l,r}\to g_{l,k}\)然后乘上中间得系数。还有\(g_{l,r}\to g_{l-1,r}\)。最后输出\(g_{1,n}\),这样是\(O(n^3\times n^2)\)的。进一步优化是考虑能否每次直走一格。那么我们需要知道右边有没有一个\(k\),所以就设\(g_{l,r,0/1}\)表示当前拓展到\(l,r\)右边有没有\(k\)的方案数。那么\(1\)的话就必须向右拓展,然后考虑当前这一位是不是钦定的\(k\),乘上系数。具体的\(g_{l,r,1}\to g_{l,r+1,0},g_{l,r,1}\to g_{l,r+1,1},g_{l,r,0}\to g_{l-1,r,1}, g_{l,r,0}\to g_{l-1,r,0}\)。乘上对应系数,最后要\(g_{1,n,0}\)\(g_{L,R,0}=g_{L,R,1}=1\),\(O(n^2\times n^2)\)。继续优化,由于转移是固定的,我们其实是找的\((L,R,0)(L,R,1)\)\(1,n,0\)的所有路径上权值乘积的和,然后到\(1,n\)输出。我们发现其实反过来也可以,就是找\(1,n,0\)\((L,R,0),(L,R,1)\)的所有路径上权值乘积的和。能这么做的原因感觉是转移和起点无关,都是独立的,并且转化成了路径权值和的问题,所以很对。这样就是\(O(n^2)\)了。然后呢,还能优化,因为我们发现这个状态和转移之和长度有关而和具体的左右端点无关,所以就能做了。

总结:对于不确定序列计数问题,找充要条件,或者找必要条件,然后对着这个做;转移和起点无关的\(dp\),如果有多次,可以尝试把他们放到一起转移,或者转成路径,从终点向起点跑(其实上面内个题费点常数应该也可以从终点跑到起点);钦定钦定;\

CF1975I Mind Bloom

这个题太难了。就是不知道这个具体是怎么想到的。考虑最终只有两种结果,赢或输(全是1的判掉),赢得概率有点难算啊,我们算输的。输的就是全\(0\)的情况。下面先说一些前置东西:1. 由于数组有序,我们可以用下标代替值。2. 当前有\(x+1\)个数,最大值是\(i\),经过几轮操作后最大值变为\(j\),并且共有\(y\)个值。那么\(j-x\)这些数被选中的概率是相等的,也就是\(\frac{y-x}{j-x}\)。接下来进入正题。由于最终全\(0\),所以手牌中的\(\max\)的整体趋势是下降的。那么我们对于一个状态\(i,x\)表示最大值是\(i\)除掉\(i\)还有\(x\)个数这样的状态,\(dp\max< i\)的概率,因为还要转移到其他状态,所以我们还需要知道变换后的数的个数,具体的我们设\(f_{i,x,y}\)表示\((i,x)\)这个状态,第一次随机到\(\max<i\),并且此时的有\(y\)个数的概率。考虑怎么求。啊这个也是感觉很跳跃。就是设\(g_{j,y}\)表示从\(i,x\)这样的状态变成\(j,y\)这样的状态的概率,有\(f_{i,x,y}=g_{i-1,y}\),初始就是\(g_{n,x+a_i}=1\)。转移。我们只关心\(j\ge i-1\)这里的值,因为要求得是\(i-1\)。考虑怎么转移。首先原来的\(x\)个数一定\(\le i-1\)。然后对于一个\(g_{j,y}\)我们要考虑\(j\)是否在这个序列里(原来得\(x\)个数\(\le i-1\),所以不会产生影响),由前面说的前置知识,我们知道在的\(p=\frac{j-x}{y-x}\),如果不在的话\(g_{j-1,y}=(1-p)*g_{j,y}\)。如果在呢?那么我们需要从\(j,y\)这个状态,走到一个\(\max<j\)得状态,也就是\(f_{j,y-1,\cdot}\),也就是\(g_{j-1,z}=\sum{p*g_{j,y}*f_{j,y-1,z}}\)。就是走到内个状态得意思。然后\(j=i\)得时候,就是\(f_{i,x,z}\)这个时候,会有一个转移环,就是\(f_{i,x,y}=B+A*f_{i,x,y}\),不过这个解一下就行了。现在我们在\(O(n^5)\)的情况下求出了所有\(f_{i,x,y}\),考虑怎么求答案。设\(ans_{i,x}\)表示在\(\le i\)的数中,除去原有就有的手牌,又抽了一些牌使得总牌数是\(x\)的情况下,输掉游戏的概率是多少。这个和\(g_{j,y}\)求得方法有点像。考虑若\(c_i=1\),那么一定有\(i\),那么\(ans_{i,x}=\sum{ans_{i-1,y}*f_{i,x-1,y}}\)。如果\(c_i=0\),就是有概率有,有的概率是\(p=\frac{x-s_i}{i-s_i}\)\(s_i\)是原有得手牌。分讨一下,若没有\(ans_{i,x}+=(1-p)*(i-1,x)\),若有\(ans_{i,x}+=\sum{p*ans_{i-1,y}*f_{i,x-1,y}}\)。最后输出\(ans_{n,s_n}\)。那么就求完了。时间复杂度是\(O(n^5)\)。常数小就过了(绷

总结:正难则反;\(dp\)可以分段来求,阶段得划分没什么固定得(观察打法)概率。如果有转移环,尝试解方程。

qoj11117. Under the Epilogue

这个题,难想难理解难实现。首先考虑一个点集怎么判断是否是正确的。考虑如果是一个回路那么一定是强连通分量,这是必要的。然后这个也是充分的,证明挺好证的。就是考虑缩点是否能缩成一个点啊,如果不能,缩成一个\(DAG\),那么此时任意两个相邻地强连通分量都不能互相到达。由这个启示,我们在原集合中不断找相连地两个(因为是一段区间,所以相连的更容易连起来)判断是否能互相到达,然后合并,最终如果能合成一个点就行。(我在胡说,根据结论猜过程)。然后就容斥\(dp\),(为什么想到呢?不理解?题解也没写)就是设\(f_{l,r,L,R}\)表示所以点\(\in [l,r],l,r\in S\),并且最远能拓展的地方是\(L,R\)的合法强连通分量数。满足上述条件得总数是好求得,减去不合法的。不合法得一定是若干段合法的拼起来,相邻两段不能互相到达,就是\(DAG\)。所以这个我们就在合法得后面一直拼。所以我们需要从大到小枚举\(l,L\)然后求出所有得\(f_{l,\cdot,L,\cdot}\)。两个相连的段\((l_1,r_1,L_1,R_1),(l_2,r_2,L_2,R_2)\),需要满足\(r_1<L_2 or R_1<l_2\)。所以我们需要知道已经拼上的最后一段的\(r,R\)和最大的\(R\),还要枚举\(l_2,r_2,L_2,R_2\),所以是\(n^9\)。关注到只有\(r_1,L_2\)\(R_1,l_2\),所以分步转移,先转移到\(l_2,L_2\),然后再转移到\(r,R\),继续就是分三类转移\((r_1<L_2)+(R_1<l_2)-(r_1<L_2 and R_i<i_2)\),最终变成\(n^6\),常数小啊能过(绷。但是还没想出来怎么实现\(n^7,n^6\)

总结:?结论有点多。如果限制只在几个元素里面,那么可以分步转移;转移限制可以尝试容斥转移,看容斥后的转移会不会简单一些。

AT_arc183_e [ARC183E] Ascendant Descendant

自然的想法是找出可达区间,因为树的原因,所以可达区间不是包含就是不交,(关键性质但是没想到)。然后如果有一个区间\(l,r\)满足\(\forall i\in [l,r],[l_i,r_i]\in [l,r]\),那么就不能从\(<l\)部分走到\(>r\)的部分。如果把这些区间删掉,那么一个\(i\)向左右拓展到的点都是可到达的(不能越过这些区间)。证明考虑归纳,按照区间长度从小到大往后推。然后答案统计。就是按可达区间长度从小到大枚举,在\(l_i,r_i\)(不能越过上述区间)中找还会剩下几个位置能选,然后乘上方案,随便选一个点把他标成选过。如果有相同的数并且可以相互到达,那么方案会算重,所以我们需要除以阶乘。代码先咕一下。

总结:遇到与树相关的区间,思考是否满足不是包含就是不交。

sez993

这个题还挺好的。好题。问题主要在于怎么判定这个重复子串。考虑长度为\(2L\)的串。我们把区间按照\(L\)分块,设串的中间点为\(i\),其所在块的左端点为\(j\),右端点为\(k\),那么就会串就会被分成3个或2个串,左半部分在\(j\)前面的与右半部分在\(k\)前面的相等,左半部分在\(j\)后面的与右半部分在\(k\)后面的相等,发现一个是前缀一个是后缀并且是可加的,那么我们考虑,如果设\(S[1\sim j-1]\)\(S[1\sim k]\)\(LCS\)\(x\)\(S[j\sim n]\)\(S[k+1\sim n]\)\(LCP\)\(y\),那么在\(j\sim k\)中存在一个\(i\)的充要条件是\(x+y\ge L\)。那么我们只需要枚举\(L\),找整点就行了。第二个方法更好理解。就是实际上我们要找两个后缀\(i,j\)\(LCP\ge j - i\),那么我们先建出来\(sa,height\),然后再从大到小枚举最小值,不断地合并一些区间,问题就变成了是否存在一段区间中的数的最小\(j-i\)是否$\ge $当前的最小值。这个使用线段树合并做就行了。

总结:第一种方法有点难想,但是第二种想法就比较自然了,想到了转化后的问题了,但是没有办法很好的维护,加练数据结构;在字符串中,把一个字符串切割成多个字符串再进行计数的方法有点常见。

Qoj9492

这个有点像别样的根号平衡,思路还挺好的感觉。我们把修改差分,这样再第\(2\)颗树上进行单点查询就变成了第一颗树上的子树查询,然后我们可以做到修改\(\sqrt{n}\),单点查\(O(1)\)。具体的就是把\(dfs\)序分成\(\sqrt{n}\)个区间,记录\(pre_i\)表示\(i\)到其所在块左端点的前缀和,\(suf_i\)表示到右端点的和,\(preb_i\)\(i\)个整块的和,这样就能做到了。但是这样查询一次\((x,y)\)还是\(O(n)\)的,接下来的做法比较巧妙。就是选择\(\sqrt{n}\)个关键点,使得任意一个点到最近的一个关键点的距离小于等于\(\sqrt{n}\),先处理出其到关键点的和,复杂度\(\sqrt{n}\)。还需要处理出来关键点之间的信息,这个我们可以差分一下变成到根的信息。因为只有\(\sqrt{n}\)个点,我们考虑对关键点使用\(O(n)\)的复杂度求出所有时间这个关键点的值,我们设这个关键点到根路径上的点为黑点,设\(s_i\)表示再第一颗树上\(i\)到根路径上有多少个黑点,就是\(i\)贡献了多少次。这个就差分一下就行了。那么我们就得到了\(O(n\sqrt{n})\)的做法。还有一个问题是如何选择这\(\sqrt{n}\)个关键点。我们只需要\(dfs\)一遍然后把是\(\sqrt{n}\)倍数的点标记一下就行了。

总结:这个修改\(\sqrt{n}\),查询\(O(1)\)的方法有点新奇。

CF1476F

这个我应该是听过做法的。就是设\(f_i\)表示利用\(1\sim i\)中的点最多能练到连续的\(1\sim f_i\)。然后对\(i\)选左还是选右分讨转移。

loj6406

感觉这个挺好的啊。首先我们先不排序,就按照原来的顺序看所有的序列,看他们的概率。分母肯定都是一样的\(\frac{(n+d-1)!}{(n-1)!}\),分子呢,分子就是\(\prod (a_i-1)\),(下面我们令\(c_i=a_i-1\))。但是不同的操作顺序可能到达同样的状态,那么一个状态能到达的操作数就是\(\frac{d!}{\prod c_i!}\),那么这一个状态对应的分子就是\(d!\)。!惊奇的发现这个,不同状态的概率是固定的。然后下一步转化有点问题。本来转化成了找前\(r\)大和为\(k\)的方案数,但是这样不太好做啊。正解是,由于每个状态的概率相同,所以我们只需要找到一共有多少不同的状态,和所有状态前\(r\)大的总和。找这两个的方法也比较好。设\(cnt_{i,j}\)表示使用\(i\)个数表示出\(j\)的方案数,\(sum_{i,j}\)表示这些方案中前\(r\)大值的和。回忆一下数划分的做法,内个的顺序固定,操作是加一个\(0\)或全局加\(1\),这样保证了是单调的,但是这个问题我们不能单调。也就说我们可以不只在最后的位置加\(0\),所以我们就枚举那些位置是\(0\),枚举不是\(0\)的位置,把这些位置\(-1\),转成子问题。具体的就是\(cnt_{i,j}=\sum_{k}^{i}cnt_{k,j-k}\),为啥不能不\(-1\),因为要满足定义枚举的是非\(0\)的位置,所以要在原来的方案上强制加\(1\)。这样还有一个好处,就是前\(r\)一定也都加了\(1\),所以\(sum\)的转移也有了,就是原来的和加上加\(1\)产生的贡献\(sum_{i,j}=\sum_{k}^{i} (sum_{k,j-k}+cnt_{k,j-k}\times \min(k,r)\)。不过这个\(dp\)咋想到的还是不太明白,\(zxy\)的解释有点看不懂啊。不过挺有用的。复杂度\(n^2d\)

总结:遇到通过操作到达最终的状态,考虑最终的状态是否有一些性质,例如由于操作而导致不同最终状态的的概率相等,分析的方式是通过中间的具体过程找到最终状态概率;概率期望题很可能是假的,原因就是上面内一点;多过程的题目,如果中间的具体过程难以维护,可以直接考虑末状态有没有什么性质,能不能直接算(贺自zxy);(第一次知道\(double\)能表示的范围比\(long long\)大,只是精度问题。。。)

P2664

调完样例直接过!!!爽飞了.
相当于是求很多条链的答案,我们把每条链放到这条链第一个作为点分治中分治中心的点进行计算。具体的设当前的分治中心是\(rt\),那么对于他的一个儿子\(v\),我们计算在\(v\)所在子树前面的内颗子树对他产生的影响。这部分我们可以先考虑弱化版就是一个序列。比较好维护对吧。这个我们考虑在\(fa_v\)的答案的基础上进行更新。当前颜色只有当到\(rt\)的路径上没有,并且在先前的点到\(rt\)的路径也没有才会产生贡献,换句话说,我们需要维护在前面的点中,有多少点到\(rt\)的路径上没有这个颜色,这个是好维护的。就是\(dfs\)一颗子树的时候,先假设都可以,如果碰见了一个从这个点到\(rt\)的路径上第一次出现的颜色,那么这个点的儿子都不行,减去即可。大概就是这个东西,然后就前后都维护一下。没有调很长时间很开心。

总结:树上所有路径问题,考虑在第一个分治点进行处理;先考虑弱化版,这个有点重要。

AT_abc221_g

这个前面的转化都挺好的,除了\(bitset\)部分。由于这个\(x,y\)是不独立的,但是每次的\(D\)对于\(x,y\)又是固定的,所以就有一个经典\(trick\),把坐标轴转\(45\)度,那么终点就变成了\((x-y,x+y)\)了,此时\(x,y\)独立。所以分开考虑。这个不是\(01\)背包,所以不太好处理,所以我们先钦定所有的都向右走,然后只看向左走的,设终点是\(t\),这就要保证\(sum>t,(sum-t)%2=0\),那么我们把终点再变成\((sum-t)/2\)(这一点很重要,优化空间)。然后跑\(01\)背包。发现还是很炸对吧。我们发现,这个是个可行性\(dp\),但是又没有状态可以放到答案里,\(01\)背包+可行性转移\(\to bitset\)优化。。。这样复杂度就是\(\frac{nV}{w}\)。就过了、

总结:遇到高维的问题,并且每一维不独立,我们可以考虑对坐标轴做一些操作使得每一个独立,例如改变坐标轴;\(01\)背包+可行性转移\(\to bitset\)优化。这点感觉还挺有用的虽然。。。

CF1442E Black, White and Grey Tree

感觉还挺好的,感觉有点构造的意思。先考虑没有灰点的状态。首先,一个相同颜色的连通块是一样的,就是删掉一个的时候一定会删掉另一个,证明我们可以考虑父子关系这样,删掉父亲时一定会删掉儿子,因为导致儿子不联通了,所以不如现在删掉,反之亦然。直接\(dp\)不太好做,就不可做。考虑是不是有什么确定的操作。一开始觉得是先删掉一个颜色,剩下的暴力删。但是这个太假了,因为这样灰点就没有任何用途了。正解是缩完点后从叶子节点开始,每次删一层,有相同颜色就删掉。设直径为\(d\),那么答案就是\(\frac{d}{2}+1\),对于链来说肯定对。对于树,我们发现,如果只保留直径上的点,把其他的点都删掉,那么答案不比原来的劣,最优能做到上述次数,所以就是对的。那么问题转化成了选灰点使缩完点后的直径最短,有一个比较神仙的做法。就是把灰点拆点。就是说,如果一个灰点连着黑点白点,那么把灰点拆成黑白点,黑点向黑点连边,白点向白点连边,被拆除的两个点连边,然后缩点,如果直连着同一种颜色,那么就染成内个颜色。考虑问什么是对的,我们考虑缩完点的黑白点谁先被删。如果黑点先删,那么就是把原来灰点连的黑点删掉,然后带着灰点删剩下的白点,反过来也是。所以这样操作是合法的。由于灰点不是被合并到白点就是黑点,所以跑出来的直径是相等的,所以就对了。

总结:有一些比较好想的,能把问题结构变得更规整的操作尽量思考;删掉一些点拆成不同连通块的,可以考虑从最外层删,这样不会破坏整体的连通性,同时可能是最优;

P6329 【模板】点分树 / 震波

好像是一个没什么用的板子。就是利用点分树的一些性质。1. 层数小于\(\log n\) 2. \(u,v\)在点分树上的\(lca\)一定在原树的\(u\to v\)的路径上,就是满足\(dis(u,v)=dis(u,lca)+dis(lca,v)\)。那么对于询问来说,我们枚举\(x\)\(y\)\(lca\),一共\(\log n\)个,那么我们只需要知道在\(lca\)的点分子树里,与\(lca\)距离\(\le k-dis(lca, x)\)的点的权值和。然后向上跳,但是会算重。此时有个需要注意的点,就是点分树的距离和原树上的距离没有关系,就是要减去\(lca\)\(x\)方向上的子树\(s\)中的值,就是查询在\(s\)子树里有多少到\(lca\)(注意是\(lca\))的距离\(\le k-dis(lca,x)\)的。所以需要维护两个动态开店树状数组。

总结:板子。在处理多个待修改的路径问题或者连通块问题,可以使用点分树。

CF1517F Reunion

这个,设点集\(S\)的答案是\(f_S\),那么答案就是\(n-1+\sum_{S}f_S\to n-1+\sum_{r=1}^{n-1}r\sum_{S}[f_S==r]\),此时限制有些麻烦,因为是恰好等于,由于前面有一个\(r\),所以我们可以进行一个转化,\(\sum_{r}\sum_{S}[f_S\ge r]\)。这个看起来比刚才内阁简单,就是对于每一个\(r\)求有多少个大于等于\(r\)的。枚举\(r\)。设有空的是白点,否则是黑点。接下来定义预备点为子树里最近的黑点里他的距离大于\(r\)的点。合法的预备点为当前预备点不会受到其他子树的影响的预备点。设\(f_{i,j}\)表示\(i\)子树里最近的黑点离\(i\)距离为\(j\)且没有合法预备点的方案数,\(g_{i,j}\)表示\(i\)子树里最深的合法预备点离\(i\)距离为\(j\)的方案数。考虑转移。\(f_{i,j},f_{v,k}\to f_{i,min(j,k+1)},g_{i,j},g_{v,k}\to g_{i,max(j,k+1)}\)。然后分讨,当\(j+k+1<=r\)时,\(f_{i,j},g_{v,k}\)此时\(g\)中预备点会被前面的子树影响,所以就不是合法的转移到\(f_{i,j}\),否则转移到\(g_{i,k}\),同理\(g_{i,j},f_{v,k}\)一样。最后的答案就是\(\sum_{i=0}^{n}g_{1,i}\)。注意减去全白的方案,这个是特殊情况。
思考路径应当是,子树里最近的黑点距离\(>r\)\(f\),上面存在点\(\to\)预备点\(g\),若存在合法的预备点则不关心当前最近的黑点,否则关心,所以\(f,g\)是互斥的。初始话就是\(f_{i,0}=g_{i,0}=1\)分别表示\(i\)是黑白点的方案。

总结:恰好等于问题一般不如大于等于问题好解决,根据式子转化成钦定或其他;

P5443 [APIO2019] 桥梁

感觉这是一种比较新的平衡方式,对操作分块。字面意思,我们需要把操作分块,设块的大小为\(B\),那么边可以分为两种,1. 在本块内未被修改2. 在本块内修改了。第一种边有\(O(n)\)个,并且不受本块中的时间影响,第二种只有\(B\)条。那么对于一个块内的,我们把第一种边排序,把询问也排序,然后从大到小做这个问题,在处理一个询问的时候,满足条件的第一类边已经都放进去了,对于第二种边暴力加入,使用可撤销并查集进行撤销,答案就是所在连通块的大小。这样就做好了。时间复杂度,对于第一种边复杂度是\(\frac{q}{B}m\log m\),第二种边的处理是\(qB\log n\),所以\(B\)\(\sqrt{m}\)或其他的,总复杂度是\(q\sqrt{m}\log n\)

总结:对操作分块第一次见到,操作和查询同时,受时间影响,可以考虑对操作分块。

CF757G Can Bash Save the Day?

!!!首道黑!!!嘿嘿嘿。
点分树太厉害了。因为我们可以把排列反过来看,就是对每个点有一个权值\(k\),每次更改两个点的权值,每次询问权值处于\(l,r\)之间的点。那么我们在每个节点点开一个动态开点树状数组,把儿子里的权值离散化一下,查询就是板子内样,修改的时候就分讨一下是不是两个都在这个子树里面,也比较好改。爽

P1654 OSU!

远古老题了。期望学的稀烂啊。这道题的核心应该是考虑增量的期望值。\((x+1)^3=x^3+3x^2+3x+1\),增加的部分是\(3x^2+3^x+1\),我们要维护每一个位置增加量的期望。所以还要知道\(x^2\)的期望和\(x\)的期望,设\(x1_i\)表示从\(i\)往左数连续\(1\)个数的期望,有\(x1_i=(x1_{i-1}+1)*p_i\),设\(x2_i\)类似的表示。\(x2_i=(x2_{i-1}+2x1_i+1)*p_i\),那么\(ans_i=ans_i-1+(3{x2_i}^2+3{x1_i}+1)*p_i\)。后面的就是期望增加量。

总结:与不同位置有关的值,考虑维护期望增加量。

P2824 [HEOI2016/TJOI2016] 排序
这个题好难啊。。。普通的排序太困难了,但是\(01\)排序就很好做。于是我们尝试怎么做成\(01\)排序,考虑最后的数为\(x\),把\(\le x\)的数设成\(1\),否则\(0\),发现若\(y>=x\),则第\(q\)个位置是\(1\),否则是\(0\),换句话说,有单调性。。。。然后就二分答案、

总结:这个题感觉是恰好是这个数转成了\(\ge\)这个数,感觉还挺巧妙的。

乘积特别大的值比较,可以用\(\log\)值比较。

CF799F Beautiful fountains rows

题解看完了,感觉比较神奇啊。首先我们知道奇数个相同的权值异或起来等于这个权值。偶数个就等于\(0\)。于是我们可以给每个区间随机异或相同的值。但是题目要求询问奇数的情况,不太好维护,考虑怎么让我们变成查询\(0\)我们把一个数删掉就变成偶数了对吧很nb,考虑怎么删才能查询起来没问题。答案是把区间的左端点删掉。但是这样查询有时候会出现问题,就是查询一个区间\([l,r]\),当\(l-1,l\)都是\(1\)的时候,如果查出来是奇数还是偶数没变,根据刚才的思想,我们再删一个数,把\(l\)删掉,改成查询\(l+1,r\)(感觉很牵强)。这样做对所有情况都是对的。那么问题转化成了有多少个\([l,r]\)能使\([l+1,r]\)异或和为\(0\),设\(sum_i\)表示\(1\sim i\)的异或和,那么刚才的条件可以写成\(sum_{l}\oplus sum_r=0\to sum_{l}=sum_{r}\),剩下的就比较好做了。最后把全是\(0\)的减去。

总结:有关奇偶的限制可以用异或和限制;查询区间有奇数个数可以通过上述操作转化成查询区间有偶数个数。

uoj950

这个要关注到一个关键性质:由于\(s+a_i,a_i\leftarrow -a_i\),所以:\(s\)+\(1\)的个数始终不变。所以最后\(1\)的个数就是\(s\)+\(1\)的个数\(\mod (n+1)\)。那么我们需要知道,序列中有\(f_i\)表示\(i\)\(1\)的概率是多少,这个组合数就能求。接下来就求两个多项式相乘的系数就行了\(p\)\(f\)相乘,啊这个用\(FFT\)

总结:有好多变量在变的情况下,并且不太好维护,寻找变量与变量之间是否有不变的关系,对这个做;两个多项式相乘考虑使用\(FFT\)

UOJ514 通用测评号

引理:如果坑满了也能继续放球,答案不变。设\(E[X]\)表示当前状态到达最终状态后的期望值,那么\(E[X]\)有概率转移到自己,也有转移新的状态,可以解一个方程得到期望和原题一样;第二种方法是把转移到自己的状态视为等待状态,这样到达一个新状态的概率是不变的,就是关心的状态是不变的。可以举一个比较形象的例子,就是投一枚\(1\sim 6\)的筛子,只记录投出的\(1\sim 5\)的数,投到\(6\)就再投一次,得到的期望和直接投\(1\sim 5\)的骰子是一样的;
推论:反过来,如果原问题是放满了也能继续放,那么这个的期望和概率和放满了不能放是一样的,原因和之前是一样的,相当于直接删掉等待时刻;
这两个挺有用的。
坑的地位是相同的,根据期望的线性性,我们把最终的答案拆分一下,\(E[X]=n*P(\text{所有坑}\ge b\text{第一个坑}\ge a)\),直接求不好求,我们求他的对立,求没到\(a\)的概率。于是我们把第一个坑的容量设为\(a\),其他坑的容量设为\(b\),操作是每次向没满的加球。根据推论这个是对的。那么我们求得就是最后一个放球放到第一个坑的概率。那么我们有\((n-1)b+a\)的操作序列。每一个操作的概率是\(\frac{1}{\text{没满的坑数}}\),由于不能把整个序列记录下来,并且剩下的坑其实是相同的,所以就先再位置上空一些位置,等一些位置要满的时候,把操作序列都填上。具体的,设\(f_{i,j}\)表示当前有\(i\)个坑满了,有\(j\)个操作位置没填的概率,如果当前填使得一个坑满了,\(\frac{n-i-1}{n-i}\binom{j}{b-1}f_{i,j}\to f_{i+1,j-(b - 1)}\),如果无事发生,\(\frac{1}{n-i}f_{i,j}\to f_{i,j+1}\)。最后的答案就是\(f_{n-1,a-1}\);第一个转移里,是我们考虑是哪一个在这一步满了,不过这个也可以在最后乘上\((n-1)!\)来解决

总结:如果每次操作概率相同,且一个操作不改变当前的状态,那么把这个操作加入进去不会改变答案;同理,如果一个操作满足这样的性质,删掉也行;若所有数的地位相同,那么我们可以把答案拆成一个的概率乘数量;当序列太大而无法记录时,通过把一些位置空出来,在最后再进行计算贡献;

P3239 [HNOI2015] 亚瑟王

如果我们知道了每张牌发动的概率\(g_i\),就能求了。考虑如何求这个概率;从\(1\),开始,由于前面没有牌,所以概率就是\(1-(1-P_1)^r\)。看\(2\),分两种情况,1. 1没发动,在这种情况下答案就是\(1-(1-P_2)^r\),2. 1发动了,这种情况下有一轮\(2\)是发动不了的,所以在这种情况下的概率就是\(1-(1-P_2)^{r-1}\);有这个启发我们,第\(i\)个数发动的概率,只和前面有多少牌已经发动了有关,那么我们就设\(f_{i,j}\)表示前\(i\)张牌,有\(j\)张牌在\(r\)轮种发动过的概率是多少,转移是好说的,按照刚才的方式转移就行。求\(g\)同理,也是通过刚才分讨进行转移;

总结:期望转成概率;求概率的题,可以从小情况递推,向下转移的时候分情况转移,关注比较优秀的性质例如只和个数有关,而不是和剩下具体的数是什么有关(话说这个东西好像文化课也要用);

P3750 [六省联考 2017] 分手是祝愿

重要的观察是,最优操作是从后往前跑,如果\(a_i\)等于\(1\),就操作。还有一个观察是,一个操作不可能被替换成其他的操作叠加起来;有了这两个就好说了,因为我们需要操作的序列就有了。考虑一次随机会产生什么影响,如果选到了操作序列的数,就把操作序列中的这个数删掉,否则就加到操作序列里。那么发现,我们不关心具体数值,只关心当前有多少个数,于是设\(f_i\)表示操作序列有\(i\)个数,到达\(\le k\)的操作序列数的期望步数是多少。转移就分讨一下,\(f_{i}=\frac{i}{n}f_{i-1}+\frac{n-i}{n}f_{i+1}+1\),解方程就好了。

总结:由于改所有约数的操作确定,所以操作序列就确定,就得到做法了;设状态,如果具体的数值没法很好的记录下来维护,那么就考虑转移和具体数值的关系(结合性质)

P3830 [SHOI2012] 随机树

好题。第一问简单不赘述。考虑第二问,重要的转化是因为贡献是\(max\)所以我们可以转化成\(\ge x\)的概率是多少。于是,设\(f_{i,j}\)表示\(i\)个节点的随机数,深度\(\ge j\)的概率。那么怎么转移,可知,左右两颗子树深度至少有一个大于\(j-1\),因为节点数不同会影响概率,所以要枚举左右两颗子树的大小,设左子树叶子数为\(k\),那么右子树就是\(i-k\),那么达到这个状态的概率是多少?我们可以参考绿宝石之岛的做法,不难分析出是\(\frac{1}{i-1}\),所以转移就有了\(f_{i,j}=\sum_{k=1}^{i-1}(f_{k,j-1}+f_{i-k,j-1}-f_{k,j-1}*f_{i-k,j-1})*\frac{1}{i-1}\),因为是条件概率,再子树叶子数确定的情况下才是这个概率,所以乘\(\frac{1}{i-1}\)。最后输出\(\sum_{i=1}^{n-1}f_{n,i}\)。关于设状态,我们可以这么想,题目其实可以转化成一个集合\(S\),每次等概率选出一个数\(x\),删掉\(x\),加入\(x+1,x+1\)。设\(h_{x,i,y}\)表示,集合从\(x\)开始,经过\(i\)此操作,最大值\(\ge y\)的概率是多少,转移就是先进行一个操作得到新集合表示\(\left\{ x+1,x+1 \right\}\),然后就讨论再第一个\(x+1\)和第二个\(x+1\)分别进行了几次操作。但是这样转移是\(n^4\)的,瓶颈在于集合初始不同。但是,我们发现,由于操作类型固定,所以我们可以认为集合都是从\(0\)开始的,把最大深度\(+1\)就行了,所以就省掉了\(x\)那一维,就来到\(n^3\)了。

总结:遇到期望中贡献的值就是其权值时及\(E(X)=\sum xP_x\),那么我们可以转化成求\(\ge x\)的概率,然后直接加起来就行了;优化\(dp\)时,如果状态初始不同而导致复杂度爆炸,寻找转移到的新的状态与当前状态有没有确定的关系和最终结果与初始状态的相对大小,进行优化;

P6348

这个线段树优化建图,由于是区间向区间连边,所以我们可以通过建一个虚点来实现\(\log n\)条边。把\(1\)边权拆成两份,到一个虚点权是\(\frac{1}{2}\),实际写的时候边权写\(1\),答案\(/2\)就行。使用\(01bfs\)就行了。

总结:若一个区间和一个区间连权值相同的边,那么可以通过建虚点的方式减少边数,代价是加多点数。

CF1610G AmShZ Wins a Bet

如果要删掉一个\((\),那么必定会选择离它最近的\()\),同理如果要删掉\()\),那么就会选择离他最近的\((\)。有这两个我们可以得到每次删除删\(()\)是最好的。有这个我们继续推导,对于最后的操作序列,我们删掉的一定是多个合法括号序,因为如果\(()\)里面还有东西,就不会删除它。那么问题就变成了,删掉一些合法括号序,使得最终的字典序最小。字典序做法没怎么见过。从后往前\(dp\),设\(f_{i}\)表示\(S[i\sim n]\)的字典序最小的串是什么,考虑转移。对于\(i\)来说,有两种选择,不操作\(s_i+f_{i+1}\),操作,\(f_{nxt_i+1}(nxt_i)\)表示从\(i\)开始的合法括号序的右端点,所以\(f_i=\min(s_i+f_{i+1},f_{nxt_i+1})\)。怎么比较,就是用反串建字典树,倍增向上跳,用哈希判断等。时间复杂度\(O(n\log n)\)

总结:最优化问题,可以先判断操作是否是固定的,若固定,判断答案,操作过程,有什么性质;使字典序最小的\(dp\),可以从后往前\(dp\)

P4390 [BalkanOI 2007] Mokia 摩基亚

加一个时间轴,就是\(cdq\)分治了。感觉用的太少啊,看了标签才知道。

总结:如果边查询边修改二维上的,那么考虑离线用\(cdq\)

CF1192B Dynamic Diameter

感觉还挺好的,增加了欧拉序的办法。考虑,一条\(u\to v\)的链的长度怎么求,\(dis_u+dis_v-2*dis_{lca}\)。但是我们不可能存所有的边。但是我们关注,在欧拉序中,\(u,v\)出现的位置中间的点,深度最小的就是他们的\(lca\),而这样的的结构可以写成\(u,lca,v\),所以我们只需要建出欧拉序,找出最大的\(u,lca,v,dis_u+dis_v-2*dis_lca\)即可。对于每个节点,我们维护\(L\)表示\(\max(dis_i)\),\(M\)表示\(\max(-2dis_M)\),\(LM\)表示\(\max(dep_i-2dep_j),i\le j\)\(MR\)表示\(-2dep_i+dep_j,i\le j\)\(LMR\)表示\(dep_i+dep_j-2*dep_k,i\le k\le j\)。合并就分讨一下。而修改操作,由于欧拉序也满足\(dfs\)序的性质,所以其实就是区间加。然后就做好了。

总结:欧拉序可以处理直径,\(lca\),剩下的不知道了,感觉用处还挺大的;维护一个序列几个数相加和,要求有下标关系的,可以在线段树节点上维护前缀和后缀极值,然后合并就行。

CF1368H1 Breadboard Capacity (easy version)

如果\(n,m\)很小,那么我们可以考虑使用网络流,具体的就是\(S\)向红色连边,\(T\)连蓝边,格子中得点向四周连边,跑最大流就可以了。但是会爆。然后最大流等于最小割,这个问题等价于我们找最小割,我们把最终割出来得包含\(S\)得点集中的点都染成红色,包含\(T\)得点都然后蓝色,那么问题就是红连蓝得边数。现在就变成了确定染色方案得问题了。我们先给所有得点都染成红色,然后考虑蓝色点一定不能被红点包围,这样再染成红点一定更优。也就是说蓝点组成的连通块一定连着边界。接着考虑,如果蓝色组成的连通块从一个边到了一个相邻得边,那么我们把这个连通块都替换成红色也是不劣得对吧。还有一种操作是从一边到对边,但是有拐弯,这个通过小学知识也能知道是不如直着走优得。最后,不可替代得操作是一行或一列改,刚才得操作之所以能够被替代是因为改变优化的边数大于变劣得操作,即使再最坏条件下也不会变得更劣,但是一行一行这样优化的边数等于变劣的边数,所以最坏条件下可能变劣,所以要对这个做。分两种做,一个是一行一行加,一个是一列一列加。那么设\(f_{i,0/1}\)表示\(i\)行/列是红/蓝色所需要最少的红连蓝的边数,转移就行。

总结:问题转化;最优化问题寻找最优操作;网格题好像好多都和网络流有关?

sez969

道心破碎了。设我们最终拓展到了\(S\),那么答案就是\(\sum_{i=1}^{min(n, S)}-(S-1)\)。所以我们发现其实最终的答案只和最终拓展到位置有关。并且\(S<2n\)因为如果到达\(n\)了就不会再拓展了。那么现在问题转化成了能否到达\(S\)了,设\(f_{i,j}\)表示要考虑\(i\),最远拓展到\(j\)是否可行。\(n^2\)可以转移。然后由于是可行性\(dp\),所以可以用\(bitset\)优化。

总结:由于没有转换出来题意,爆了。感觉和电子运动有点像,就是一个数不是加到得分中就是加到拓展中,所以总和是不变的,最终得出答案是多少。太菜了怎么办。

sez968

反悔贪心好难TAT。就是考虑如果我们可以攒攻击,然后一起释放,也是对的,啊这个倒是想到了。然后一开始想的是设\(dp\),然后能打就打,不能打拉到,记一个最多击杀数前提下得最大剩余攻击次数,但是这样肯定不对。此时反悔,考虑如果不能打,就是说当前最小操作次数(就是让\(B\)发挥最大价值)大于剩余次数。那么我们在前面找一个攻击过得,并且最小攻击次数最大,把他的攻击次数拿过来给当前得,如果能打,就判断能不能让剩余攻击次数更大,能就拿过来,不能就保持现状。这样就对了。。。

总结:当一般贪心不对得时候,考虑反悔贪心。尽可能的简化题意。

sez970疯狂 vME X 50

首先极小的\(mex\)总共\(O(n)\)个,证法找法详见这里。然后问题就转化成给定一些区间\(l_i,r_i,v_i\),询问一个\(L,R\)中,\(\max_{L\le l_i\le r_i\le R,r_i-l_i+1\le k}(v_i)\)了。这个三维偏序能做到\(n\log^2 n\)。优化,如果\(l_i\le R-k\)那么\(r_i-l_i+1\le k\)就能满足\(r_i\le R\)了,这个二维偏序做。反面\(R-k+1\le l_i\le r_i\le R\),那么\(r_i-l_i+1\le k\)也满足,也二维偏序。所以复杂度就是\(n\log n\)了。

总结:极小\(mex\)的数量;有一维是区间长度的,三维偏序可以变成两个二维。三维偏序尝试通过分讨变成二维偏序(感觉本质上是限制条件是两个而不是三个欸?感觉可以通过这个来减少复杂度);区间\(mex\)可以通过主席树求。

P12753 [POI 2017 R3] 披萨配送员 Pizza delivery

读错题了啊我去。。首先有一些观察出来的性质。1. 如果不能直接回去,并且只有一次操作,那么答案就是边长度和乘\(2\)。2. 一次操作,最后一个结束的点一定是深度最大的点,这样最优;然后没了。接下来咋做,如果我们要在\(v\)处结束,设\(u\)表示\(v\)的祖先中,第一个还没有遍历完所有子树的点,那么必定还要到达\(u\)拐到其他子树,那么结束操作能优化的时间就是\(dep_v-2*dep_u\)了。对于一个子树\(u\),最后一个成为结束点的点会跳到\(u\)上面,其他的都是\(u\)上面,所以,我们能知道,让深度最大的点成为最后一个成为结束点的点是最优的,因为我们要取前\(k\)大值,如果有一个更短的位置与其交换顺序,虽然总和不变,但是最大值变了,这也能说明我们这样选是不劣的,所以就对了。类似长剖,在每个节点维护一个最长链,除了这个链,其他的都是跳到\(u\)这个节点,最长链在上面维护。

总结:好好读题;观察操作带来的收益与什么有关,找到最优的时候;感觉也是反悔贪心。

P8339 [AHOI2022] 钥匙

模拟,碰到一宝箱用最新获得的钥匙。于是我们考虑,如果能求出每个钥匙\(u\)点,有多少个点\(v\)满足恰好,到\(v\)的时候恰好用上\(u\)。那么我们得到了若干路径\(u\to v\),我们给他设一个\(1\)的权值,对于一个询问,我们只需要寻找包含于询问路径的路径的个数。现在怎么求出这个路径。肯定是同一种颜色的才能产生这样的路径,所以对每个颜色分别建出虚树,然后从一个钥匙的地方开始\(dfs\),暴力跑出以这个点为起点的路径,由于同种颜色的钥匙\(\le 5\)个,所以这部分复杂度就是\(5n\)。然后考虑怎么询问包含于一个路径的路径条数。和上上个题还有点联系,上上个是链的特殊情况。考虑现在怎么做。我们把得到的路径分为三种1. \(u\to v\)\(LCA(u,v)!=u,LCA(u,v)!=v\),同样有一个满足这个的路径\(x\to y\),能产生贡献是当\(dfn_u\le dfn_x\le dfn_u+siz_u-1,dfn_v\le dfn_y\le dfn_v+siz_v-1\),这个相当于矩形加单点查,差分后二维偏序,2. \(u\to v,LCA(u,v)=u\),同样满足这个限制的\(x\to y\)(注意第\(1\)种边也要加进来),同样讨论一下得到一些限制,3. \(u\to v,LCA(u,v)=v\),同理。由于这个题是有方向的,所以要这么做。做三个二维偏序就行了。

总结:虚树要利用好啊;给定路径,查询一个路径包含(于)多少给定路径,可以通过分讨转成二维偏序问题。尽量的简化问题,对于一个元素,把与这个元素贡献无关的元素删掉再考虑。

P3045 [USACO12FEB] Cow Coupons G

这个反悔贪心。先按\(c\)排序,前\(k\)小一定会在最终的答案中。考虑剩下的怎么办。有两种操作1. 强行买下,代价\(p_i\),2. 把原来使用优惠券的撤销给这个用,代价\(p-c+c_i\),这里为了最优使用\(p-c\)最小的值。使用堆维护就好。。感觉还是没有理解透,虽然感性上觉得挺对的,交上去也对了。

P1852

感觉挺有意思的,这个看起来就是要差分做,那么我们保留\(a,b-a,c-b,(a<b<c)\)。设为\(a,x,y\),操作分为四种\((a,x,y)\to a+x,x,y-x,\to a-x,x,y+x,\to a,x+y,y,\to a,x-y,y\)。操作过程中时刻要保证\(x,y\)都大于\(0\)。然后我们发表一个暴论,当\(x,y\)变成\(\gcd(x,y)\)时候,如果正向和反向的\(a\)是相等的就对。因为到达内个状态后,由于两个之间的距离是相等的,所以操作就比较少,如果想要到同样的差分状态还是现在这个状态(我猜的)。然后就做两遍,然后把操作的最长公共前缀删掉就是最少操作次数(也是我猜的,但是感觉挺对的,因为操作本质上相当于一个链,去掉相同的链就行了)。

总结:构造题,尤其是操作题,考虑把状态以同样的规律推到最终状态,以最终状态判断是否可行。最小操作可以通过两边去重得到。

P8747 [蓝桥杯 2021 省 B] 双向排序

啊这个力大砖飞了,用线段树分裂合并,发现只有两个部分,单降得和单增得,然后用权值线段树维护,操作用线段树分裂和合并做。

P12230 【模板】集合幂级数 exp

这个是板子。对于\([x^S]e^{F(x)}=\sum_{i\le 0}\frac{F^i(x)}{i!}\)我们有一个新的理解。就是选出\(S\)集合有多少不同的方案,注意这里说的不同方案是选定的集合不同,没有顺序。也是他的组合意义。因为是板子所以就直接做(贺)了。就是钦定一个枚举顺序,大的先枚举,我们想要求\([x^S]\),设\(S\)中最大的元素是\(u\),那么\([x^S]e^{F(x)}=\sum_{u\in T,T\subseteq S}[x^T]F(x)\times [x^{S\setminus T}]e^{F(x)}\)。那么从小到大枚举\(u\),设\(S\setminus u=S_0,T\setminus u=T_0\),那么我们就相当于是用\([x^{S_0|u}]F(x),[x^{T_0}]e^{F(x)}\)更新\([x^{S}]e^{F(x)}\) \(S_0,T_0\subseteq\left\{ 1,2,3,\cdots,u-1 \right\}\)。那么这个是一个子集卷积。那么就做好了,不需要逆元。复杂度\(\sum_{i=1}^{n}i^2 2^i\),不知道怎么分析到\(n^22^n\)的。

posted @ 2026-04-28 19:46  lghjl  阅读(12)  评论(0)    收藏  举报