新建这篇博客的时候发现自己在NOI之后只发过两三篇博客,而且都基本上没什么实质性内容。
果然是巨大混混人啊。
本文承接上篇(不过好像烂尾了),旨在记录一些有趣(?)的内容。
12.23
北大集训过去好些天了。
对退役这件事情几乎无感,IOI也并非自己所坚信的道路。
但这也只是逃避的说辞罢了。
不过有一说一,退役二字本身还是很让人沮丧的。至少不能够把这种挫败感带到机房传染给学弟们。
以后还是会做点题什么的,毕竟在近一两年里总还是会被打上,或者说需要依赖于这引以为傲的OIer标签的。
当然也会有些别的计划,在此就不多提及了。
下午补了USACO的题。T3那个数数题在北大集训前鼠就跟我讲过但好像当时......根本没有脑子?
「USACO 2019.12 Platinum」Greedy Pie Eaters
首先可以认为每个区间都对应一头牛(若不存在可以认为牛的体重为\(0\)),记\(A_{l,r}\)表示区间\([l,r]\)对应的牛的体重,显然最终会选出恰好\(n\)头牛,每头牛吃恰好一个派。
考虑区间dp。枚举区间\([l,r]\),并枚举区间内最后一个被吃掉的派\(k\)。
\(f_{l,r}=\max_{l \le k \le r}\{f_{l,k-1}+f_{k+1,r}+g_{l,k,r}\}\),其中\(g_{l,k,r}=\max_{l \le x \le k \le y \le r}A_{x,y}\)。
\(g\)可以和\(f\)一起算,即\(g_{l,k,r}=\max\{g_{l+1,k,r},g_{l,k,r-1},A_{l,r}\}\),可以把其中一维用滚动数组优化掉。
code
「USACO 2019.12 Platinum」Bessie's Snow Cow
直接用\(\text{std::set}\)维护每种颜色的子树并,再安排个树状数组支持区间加区间求和就完事了!!1
code
「USACO 2019.12 Platinum」Tree Depth
一件(众所周知的)事情是设\(f_{n,k}\)表示逆序对数为\(k\)的\(n\)阶排列的数量,那么其生成函数\(F_n(x)=\sum_{k\ge 0}f_{n,k}x^k\)满足
\[F_n(x)=\prod_{i=0}^{n-1}\sum_{j=0}^{i}x^j=\prod_{i=1}^{n}\frac{1-x^i}{1-x}\]
大致含义是考虑排列的生成方式,每次在一个\(i\)阶排列的末尾添加一个新的数字,根据新添加的数字与原数的大小关系可以得到逆序对数的增量。
另一件(众所周知的)事情是在考虑排列中某个位置在对应的笛卡尔树上的期望深度时,常常根据期望的线性性,转化成考虑其余每个位置在笛卡尔树上作为这个位置的祖先的概率。具体的,一个\(n\)阶排列中,\(i\)作为\(j\)在笛卡尔树上的祖先的充要条件为:\(p_i\)是区间\([i,j]\)(或区间\([j,i]\))中的最小值,而这个概率显然是\(\frac{1}{|i-j|+1}\)。
回到原问题。考虑枚举\(i,j\),计算有多少逆序对数为\(k\)的排列满足\(i\)是\(j\)在笛卡尔树上的祖先。相当于是在插入\(i\)位置时强制其为当前最小,也即对于上述的生成函数\(F_n(x)\),把\(\prod\)中\(\sum_{k=0}^{|i-j|}x^k\)项改为\(1\)或者\(x^{|i-j|}\)(根据\(i,j\)的大小关系,会发现当\(i
只需要计算出\(F_n(x)\),然后每次除掉一个\(\frac{1-x^i}{1-x}\)即可。
code
晚上口胡了下PKUWC。jlsnb!
12.24
今日不更。
12.25
今日不更。
12.26
zsy啊zsy,你不能再这样颓废下去了呀。
更一些退役后的写水题记录。
「PA 2019」A + B
咕咕
「PA 2019」Muzyka pop
先假想有一棵包含了\([0,m]\)所有数的二进制\(\text{Trie}\),那么就可以实现一个很简单的动态规划:记\(f_{x,l,r}\)表示把\(b_l,...,b_r\)选在\(\text{Trie}\)树上\(x\)节点的子树里的最优解,转移时枚举\(k \in [l-1,r]\)表示把\(b_l...b_k\)放到\(x\)的左儿子,剩下的放到右儿子,那么此处便产生贡献\(a_{k+1}+...+a_r\)。
可以发现这棵二进制\(\text{Trie}\)除了表示\(m\)的叶子到根的那一条链外每个点的子树都是完全二叉树,因此在动态规划中只需要记录\(x\)的深度以及\(x\)在不在\(m\)到根的链上即可,时间复杂度\(O(n^3\log m)\)。
code
「PA 2019」Desant
朴素状态压缩动态规划的复杂度是\(O(n2^n)\),需要记录每一个数字是否被选取。但直观来想,随着选取的数字越来越多,我们不再那么关心每个数字是否被选取,而只关心某些值域区间里被选取了多少数字。
对于每个\(i \in [1,n]\),将\(a_i,a_{i+1},...,a_n\)从小到大排序,设排序后为\(b_1,b_2,...b_{n-i+1}\),我们只关心每个\((b_j,b_{j+1})\)区间内被选了多少个数字(\(j \in[0,n-i+1]\),定义\(b_0=0,b_{n-i+2}=n+1\))。因此,在考虑完前\(i-1\)个数的选取后,我们只需要在状态中记录前述的每个区间被选取了多少数字即可,这个状态总量显然为\(\prod_{j=0}^{n-i+1}(b_{j+1}-b_j)\)。
考虑一下总状态数。可以发现状态数的总量不超过\(\sum_{k=1}^n\max\{\prod_{i=1}^ka_i|a_i \in \mathbb{N}^*, \sum_{i=1}^ka_i = n+1\}\)。众所周知取尽量多的\(3\)是最优的,因此在\(k=\frac{n+1}{3}\)时的最大值为\(3^{\frac{n+1}{3}}\)。所有\(k\)的最大值之和不太会分析,但显然不超过\(O(n3^{\frac{n+1}{3}})\)。鉴于状态转移是\(O(1)\)的,复杂度还算可以接受。
code
「PA 2019」Trzy kule
先小学生容斥一下变成求一个/两个/三个串同时满足限制。
一个串满足限制答案就是\(\sum_{i=1}^r\binom{n}{i}\)。
两个串满足限制,可以把第一个串变为全\(0\),记第二个串有\(A\)个\(0\),\(B\)个\(1\),答案是\[\sum_{\substack{a+b\le r_1\\a+B-b\le r_2}}\binom{A}{a}\binom{B}{b}\]
可以\(O(n)\)统计答案。
三个串满足限制,同理把第一个串变为全\(0\),记后两个串\(00/01/10/11\)组合各有\(A,B,C,D\)个,答案是\[\sum_{\substack{a+b+c+d\le r_1\\a+b+C-c+D-d\le r_2\\a+B-b+c+D-d \le r_3}}\binom{A}{a}\binom{B}{b}\binom{C}{c}\binom{D}{d}\]
枚举\(c,d\)后发现\(a,b\)有形如\(a+b \le x, a+B-b \le y\)的限制,暴力二维前缀和即可,复杂度\(O(n^2)\)。
有 点 卡 常
update:好像直接\(2^n\)减去不合法(全部超过)就行了,我是个麻瓜。
12.27
今日不更。