2020 竞赛日记 (下)
July
1
-
还是把重心放在改题上面吧。
-
[x] \(P3523\ [POI2011]DYN-Dynamite\)
给一棵 \(n\) 个点的树,书上有一些关键节点,要求你选 \(m\) 个点,使得关键节点到这些点中距离的最小值的最大值最小,求这个值 \((n,m\leq 10^5)\) 。
要求最大值最小,果断二分答案 \(d\) 。问题转化为选最少的点数来覆盖整棵树的关键节点。假如没有关键节点,这个题就是将军令,可以贪心求解;那么有关键节点能否贪心呢?
当然可以!在将军令中,我们可以选择深度最大的点贪心选择其 \(d\) 级祖先,实际上就是因为对于 \(d\) 级祖先的子树而言有以下两点:
- 子树内必须选择一个点
- 选择子树内的非子树根的其他点,既不能比根节点覆盖到更多的祖先,甚至在子树内都有点覆盖不到;而子树根必然能覆盖到整棵子树。
对于这个题目,上述两点同样成立。于是也可以贪心求解。
- 完成改题:动漫排序
2
- 完成改题:平行宇宙、电报。
- 效率太低。
3
- 期望DP和计数DP是努力的方向。在此之前,可能会先复习DP的优化(单调队列、斜率优化)。
- [x] \(P3957\) 跳房子
双端队列优化DP。关键在于合理控制进出,及时排除非法解。
4
- 考试。比较简单的考试但我并未取得理想的分数,太轻敌了。不应该!
- [x] \(T1\ restaurant\)
期望得分:100;实际得分:40。
- [x] \(T2\ olefin\)
期望得分:100;实际得分:40。
- [x] \(T3\ tromino\)
期望得分:40;实际得分:40。
题意:求用三个格子的积木覆盖 \(3\times n\) 的棋盘的方案数 \((n\leq10^{40000})\) 。
首先,我们可以将所有的摆积木的情况分为五种。
可以发现,所有的其他情况,无非就是在第 1 、3、4 种中间加若干个长条的的三格积木。故递推时,2、5 种情况直接加上,类 1 种的情况系数为 4,类 3、4 种的情况系数为 2 。
于是可以得到递推方程:
其中sum[0/1/2]
分别表示模3
意义下为0/1/2
的下标的f[]
值前缀和。
尽管可以递推,但是由于sum[]
的存在,每次要将新的f[]
加入sum[]
时,需要知道下标信息。而矩阵乘法时不支持维护下标信息的。考虑如何消去前缀和。
消去前缀和自然想到做差。用 \(f_i-f_{i-3}\) 得到:
于是就可以快乐的矩乘快速幂力!
-
总结:这次考试,审题出现了严重失误,也暴露出了很多隐患——比如再经历了很长一段时间常数宽裕后不再随手写快读,写题目时不到 \(10^6\) 不加快读。结果这次题目外面套了个数据组数,就被卡飞了。以后一定要更加冷静地看范围。做T1发现就是个完全背包的时候连样例都没有看,直接开始码,码完还过了样例。
excuse me ?结果输入方式看错,遗憾丢了 60 pts 。太不细致了! -
今天如愿以偿地大力练习了斜率优化。斜优越写越来劲。
-
[x] \(P3628\) 特别行动队
-
[x] \(P4360\) 锯木厂选址
-
[x] \(P3648\) 序列分割
题意:给定 \(n\) 个数,要求做 \(m\) 次分割,每次分割必须分割为两个均不为空的块。一次分割的贡献为左块内的数的和与右块内的数之和的积。要求最大化贡献 \((n\leq10^5,m\leq\min(200,n-1))\)。
看到”分割“时一眼认为是区间DP,但是时间复杂度实在是太高了。其实,区间DP更多是解决分割顺序会对答案造成影响的题目,而本题中如果割的点固定,答案就会固定 。 大概是盖斯定律告诉我们的?
于是可以用序列DP来做这道题目。设 f[i][k]
表示i
之前切k
次,则有状态转移:f[i][k]=max(f[j][k-1]+(sum[i]-sum[j])*sum[j])
。方程是二维的,貌似不可用斜优,但实际上由于f[][j]
必定由f[][j-1]
推出来,可以拿原序列做 \(m\) 次斜优DP求解。
5
- 考试。感觉这两次的考试比起之前容易了许多,
打脸警告。大概是花了 2h 就做完了。 - [x] \(T1\ ocd\)
期望得分:100。实际得分:100。
- [x] \(T2\ meaning\)
期望得分:100。实际得分:100。
- [x] \(T3\ fibonacci\)
期望得分:100。实际得分:100。
-
第一次 AK 啊啊啊!
-
完成改题:梦中漫步。既然是决定要认真学习期望DP和计数DP,那就不妨在这里总结一下。
-
[x] 梦中漫步
给定一棵 \(n\) 个点的树。\(q\) 次询问,每次询问从点 \(u\) 走到点 \(v\) 的期望步数。
看着这个题面就感觉是最简单的那种期望DP。 由于和的期望等于期望的和,所以我们可以转化为求每个点:到父节点的期望和每个子节点的期望)。设状态f[p]
表示 \(p\rightarrow fa[p]\) 的期望步数,g[p]
表示 \(fa[p]\rightarrow p\) 的期望步数,deg[p]
表示 \(p\) 的入度,那么有:
然后再消去分母并移项,就可以得到f[]
和g[]
的递推式了。
7
- 向阳而生。
9
- 今天考试,搜索专题。
- [x] \(T1\ light\)
预期得分:100;实际得分:30。未判重边。
- [x] \(T2\ pancake\)
预期得分:100;实际得分:100。
- [x] \(T3\ zplhz\)
预期得分:20;实际得分:30。
B 国研究出了连环阵,其是由 \(m\) 个编号为 \(1,2,\cdots,m\) 的独立武器组成的。最初,\(1\) 号武器发挥着攻击作用,其他武器都处在无敌自卫状态。以后,一旦第 \(i(i\in[1,m])\)号武器被消灭,\(1\) 秒种以后第 \(i+1\) 号武器就自动从无敌自卫状态变成攻击状态。 A 国打算用可持续爆炸的炸弹来消灭连环阵。目前,A 国科学家们掌握了 \(m\) 个武器和 \(n\) 个炸弹的平面坐标。在引爆时间内,每枚炸弹都可以在瞬间消灭离它平面距离不超过 \(k\) 的、处在攻击状态的 B 国武器。和连环阵类似,最初 \(a_1\) 号炸弹引爆,然后 \(a_2\) 号炸弹,\(\cdots\),直到连环阵被摧毁。 显然,不同的序列 \(a_1,a_2,\cdots,a_n\) 消灭连环阵的效果不同。你需要用尽量少的炸弹摧毁连环阵 \((m\leq100,n\leq 100)\)。 数据保证随机、有解。
搜索神题Orz。首先预处理出to[p][i]
数组,表示当 \(p\) 号炸弹引爆,目前轮到 \(i\) 号武器时,可以持续轰炸到第几号武器。据此,我们可以再预处理出Min[i]
数组,它是一个估价函数,表示从 \(i\) 号武器轰炸到 \(m\) 号武器的至少轰炸次数。那么我们可以这样更新:
注意:这样更新显然是不正确的。但我们需要的只是估价函数,也就是只要不比原代价大就可以了,并不需要其正确性。我们根据这个估价函数可以设计一个最优性剪枝。
设搜索状态DFS(p,cost)
表示第 \(p\) 号武器待轰炸,目前已经花费了 \(cost\) 次—— 也就是把 \([1,p)\) 号武器分成了 \(cost\) 段 。实际上,某个连续的一段武器可能可以被多个炸弹摧毁,而我们的搜索只在第一次随便确定了一个,这一个不一定是可行的,若它是不可行的,当再次修改时可能已经经历了层层回溯,效率太劣。于是我们考虑用二分图匹配来做这件事情——匹配、修改匹配。 首先枚举 \(i(i\in[p,m])\) ,表示当前这一轮能把 \([p,i]\) 之内的所有武器轰炸掉,接着枚举 \(j(j\in[1,n])\) 来尝试哪些点可以完成轰炸任务,若可以,则匹配 \(j\rightarrow cost+1\) 。匹配完后进行DFS(i+1,cost+1)
。在之后遇到冲突时,就可以类似二分图匹配那样修改了。这个优化本质上就是高级版本的可行性剪枝。
把搜索的各个阶段与当前阶段的选择看成节点进行匹配,实现高效的可行性剪枝 。太妙力!
-
[x] 总结:T1、T2 曾经做过,T3 神仙题。一定要记得判重边!!题目没写没有就是有!!
-
[x] 做了一道期望DP题。没什么别的技巧,就是根据和的期望等于期望的和进行递推。
-
[x] \(P1850\) 换教室
-
顺便学习了待修莫队。当块大小为 \(n^{\frac{2}{3}}\) 理论复杂度为 \(O(n^{\frac{5}{3}})\) 。实测当块大小 \(n^{\frac{3}{4}}\) 时速度最快。
-
[x] \(P1903\) 数颜色
10
出题人怎么说就怎么做是没有前途的。
——shrz
- 今天的考试是二分专题。
- [x] \(T1\ math\)
预期得分:100;实际得分:100。
- [x] \(T2\ contest\)
预期得分:20;实际得分:20。
有 \(2^n\) 个人进行 \(n\) 轮比赛,每个人有一个独一无二的排名。若两者的排名之差 \(\leq k\) 那么双方均有可能获胜;否则,排名小的必胜。现要求通过合理地安排比赛方式,最大化冠军的排名。
手玩了很久,完全没有一点想法(这类带点博弈性质的题目太难了),只能打表。
实际上,博弈问题中隐含了一棵决策树。父节点表示子节点之间的胜利者。从这棵决策树去考虑,就可以有一定的想法。我们先令最终的最大排名为 \(x\) 。那么一定有从根节点到叶子节点的链,链上均为 \(x\) 。继而,根据贪心的思路,根节点的另一个儿子节点应该为 \(x-k\) 。于是从根节点逐层广搜,每次贪心的选择大于 \(p-k\) 的最大排名填入就可以了。
- [x] \(T3\ triangle\)
预期得分:40;实际得分:30。
给出 \(2\times n -1\) 个数字作为最底层。上面的每层都比其下面的一层少 \(2\) 个数(头和尾),并且上面的每个数等于正下方、左下方、右下方三个数的中位数。求第一层的那唯一一个数是多少。
**中位数的题目有个套路就是二分+染色为 \(0/1\) ** 。本题恰好可以用这个方法。先二分 mid ,再讲最底层的数字染色为 \(0/1\) (是否大于等于 mid )。我们发现,递推出来的其余层的 \(0/1\) 一定也满足定义,于是问题就转化为如何借助最底层的 \(0/1\) 来推断第一层是 \(0\) 还是 \(1\) 。经过手玩可以发现:从最中间的数向两端广搜,第一次出现的两个相同的数字就是第一层的答案;若全程都是 \(0/1\) 交错,那么第一层的答案就是最边缘的数字。
- [x] \(T4\ digit\)
预期得分:50;实际得分:50。
题意:求在 \(k\) 进制下 \(l\) 位数到 \(r\) 位数中总共有多少个数,满足各个数位的和为 \(4\) 的倍数或 \(5\) 的倍数或 \(6\) 的倍数 \((k,l,r\leq10^{18})\)。
要求是 \(4\) 或 \(5\) 或 \(6\) 的倍数,所以应该记录当前的数位和模 \(60\) 的余数。设f[p][i]
表示在 \(k\) 进制下所有 \(p\) 位数中,模 \(60\) 余 \(i\) 的数的个数。那么有:
考试的时候只想到了可以优化到 \(O(r)\) 。然后正解就是通过这个方程处理出得出f[p][i]
时的所有的f[p-1][]
的系数,然后就可以愉快的用矩阵加速了。并且,因为这是个循环矩阵,所以可以进一步地优化。贴上代码。
struct Mat{
long long v[60];
Mat(int t=0){memset(v,0,sizeof v);v[0]=t;}
Mat operator *(const Mat b)const{
Mat ret;
for(int i=0;i^d;++i)
for(int j=0;j^d;++j){
int cur=(i+j)%d;
A(ret.v[cur],b.v[i]*v[j]%Mod);
}
return ret;
}
Mat operator ^(const long long t)const{
Mat ret(1),b=*this;
for(long long i=1;i<=t;i<<=1,b=b*b)
if(i&t) ret=ret*b;
return ret;
}
};
lsq的矩阵写得太漂亮了。
- 开始学习计数DP。
- [x] \(P1758\) 管道取珠
有两个管道,上管道内有 \(n\) 个球,下管道内有 \(m\) 个球。每次在上下两个管道内选择一个球拿出来。每个球只会有两种颜色,颜色相同的球视作完全相同。取完球后会得到一个长度为 \(n+m\) 的序列。显然会得到很多相同的序列。假设不同的序列的种类为 \(k\) ,其中,第 \(i\) 种序列有 \(a_i\) 个,请求 \(\sum\limits_{i=1}^{k} {a_i}^2\) \((n,m\leq 500)\)。
做的时候一直跟着题目的思路走,想到了如何求种类数 \(k\) ,然后就觉得可以在此基础上枚举某种球的颜色的数量以及位置再容斥可能可以求出 \(\sum\limits_{i=1}^{k}a_i^2\) 。事实证明,这样子非常的不可做。那么就换个思路,考虑 \(a_i^2\) 的组合意义。于是有了惊人的发现—— \(\sum\limits_{i=1}^{k}a_i^2\) 可以视作两个人同时取序列,最后取得的序列相同的方案数。然后DP即可。
数学题求式子可以借考虑式子的组合意义来转化。 Orz
11
“我要再和生活死磕几年。要么我就毁灭,要么我就注定铸就辉煌。如果有一天,你发现我在平庸面前低了头,请向我开炮。”
—— 皎月半撒花
-
花姐姐 Orz 。
-
今天的考试貌似无专题可以划分。
-
[x] \(T1\ color\)
期望得分:100;实际得分:100。
-
[x] \(T2\ keke\)
期望得分:100;实际得分:100。
-
[x] \(T3\ medal\)
期望得分:0;实际得分:80。一个乱搞的贪心竟然拿80pts?!
有 \(n\) 个人站成一圈,每个人需要 \(a_i\) 种独一无二的奖牌,且相邻两个人不能持有相同的奖牌。求至少要有多少种奖牌 \((n\leq10^5)\)。在不知道有多少种奖牌的情况下,不方便分配奖牌,结合问题具有可二分性,考虑二分答案。二分 \(x\) ,问题转化为 \(x\) 是否可行。是否可行的标准,就是在前面的人都符合要求时,最后 \(n\) 号与 \(1\) 号持有的奖牌的交集是否为可以空。从问题出发设置方程,设f[i]
表示 \(i\) 号与 \(1\) 号持有的奖牌的最小交集大小。但这样不好转移,我们还需要知道 \(i-1\) 与 \(1\) 的最大交集大小才能转移。于是设f[i][0/1]
表示 \(i\) 与 \(1\) 的最小/大交集大小(在满足 \(i\) 与 \(i-1\) 无交集的前提下)。那么有:
这样转移就可以了。
- [x] \(T4\ mix\)
期望得分:0;实际得分:0。
有 \(n\) 瓶药,\(i\) 号药与 \(c[i]\) 号药靠近时会爆炸。现有 \(k\) 个盒子,需要把药放在盒子内,且不会引发爆炸。求方案数 \((n\leq100,k\leq10^3)\) 。
基环树森林啊基环树森林!考试的时候我都鬼使神差地给 \(i\) 和 \(c[i]\) 连了边,但就没有意识到这又是基环树森林。或许是自己一直想训练计数DP想疯了,就只想着怎么用计数DP写。如果知道这是个基环树森林就会方便很多。因为盒子允许为空,所以再某个点时就随便放进 \(c[i]\) 没放过的盒子就可以了。于是基环树链上的每个节点都会贡献一个 \((k-1)\) 的因子。再考虑环上的节点。断环为链,但链上的最后一个节点还需要满足与第一个节点不放在一起。那我们不妨直接从问题出发设置状态,设f[i][0/1]
表示 \(i\) 节点不和/和第一个节点放在一起的方案数。于是就有如下转移:
设环大小为 size,最后答案乘上 \(f[size][0]\) 即可。
- 今天还写了道线段树合并的模板,以及初步学习了如何用 CDQ “乱搞”题目
- [x] \(P3224\) 永无乡
- [x] \(P3157\) 动态逆序对