【2021~2022】模拟赛乱写 Period II
棋盘
出题人编出来的做法非常精彩,给出题人点赞!
每次回答询问都 \(dp\) 一次是 \(\Theta(q^2n)\) 的,不另外赘述了
单独设一个变量 \(now\) 表示现在维护了 \([l,now],[now,r]\) 的 \(\rm{DP}\) 值,即 \(u_{i,j,k}\) 表示从 \((i,j)\) 出发,到达 \((now,j)\) 的方案数,\(d_{i,j,k}\) 类似,最后一维表示到 \(now\) 行的第几列
这样做就可以快速维护:
-
加入一个新的行:\([now,r]\) 的部分发生变化,直接用 \(r-1/r-2\) 行商的值转移就行了
-
询问:枚举 \(now\) 上每个点作为中转点,由于 \(\rm{DP}\) 过程中没有环,所以可以直接乘积
-
修改:
-
如果 \(l+1>now\),将 \(now\leftarrow r\),大力重构整个 \(d/u\) 数组
-
否则直接删去上面的行,实现的时候建议
memset
来避免边界错误
-
不难发现状态总量是 \(\Theta(qn^2)\) 的,但是每个状态只会走:在 \(now\) 下面到在 \(now\) 上面一个过程,也就是最多被计算两次 \(\rm{DP}\) 值
因为马在条约的过程中可能不经过第 \(now\) 行,那么另外计算一个 \(u_2/d_2\) 表示跳到 \(now+1\) 即可
这里注意如果再出现删除过程中 \(l>now\) 了需要让 \(now\leftarrow r-1\) 来保证定义合法性,另外统计答案的时候要斥去两行之间跳的情况来避免重复统计
构树
对该问题的解决有非常明显的刻画:\(\rm{dp}_ {x,y,z}\) 表示 \(x\) 点为根的子树里面有 \(y\) 个边被选择保留,根节点所在的联通块大小为 \(z\) 的对答案的贡献
这个 \(\rm{DP}\) 配合 \(prufer\) 序列就可以完成转移:
\(m\) 个大小为 \(\{a_1\dots a_m\}\) 个联通块所形成的树的数量是 \(\prod \limits_ {i=1}^ma_i(\sum a_i)^{m-2}\)
上面结论有个简单的证明:考察在一个树的构成方案,每条边的形成方案是连接的两个联通块大小的乘积
那么所有边的贡献相乘则结果为 \(\prod_{i=1}^m siz_i^{deg_i}\)
关注到 \(prufer\) 序列中每个点的出现次数是度数减一,求和之余还要再补充一份
那么将 \(\sum a_i=n\) 分散到每个联通块上面统计,树形 \(\rm{DP}\) 的过程中出现 \((x,t)\) 的边被断掉那么就乘 \(n\) 转移
具体形式相对容易,注意减去已经 \(ban\) 掉的边在序列里面的贡献,也就是在断开之后边 \((x,t)\) 后 分别包含 \((x),(t)\) 两个联通块连起来的方案要减一
进一步优化考虑观察最后一维必要性,考虑从一堆有标号点里面选一个的方案数是堆的大小,那么 \(dp_{x,y,0/1}\) 表示是不是选过点了,转移和上面类似
复杂度和树上背包一致,为 \(\Theta(n^2)\)
指数做法给了非常多分数让暴力选手体验也非常良好
糖
发现 \(s\to t\) 的路径是必经的,那么树变成以 \(t\) 为根
对于必经路径上的每个点,小 A到这个点的时候有“找一个点对应的子树钻进去”的决策,那先处理在树里面的路径形式:
设 \(dp_x\) 表示在 \(x\) 子树里面走的最小操作次数,转移显然是上来 小 B 找到 \(f_t\) 最大的 \(t\) 毙掉,然后 小 A 钻到次大子树里面,小 B 毙掉根节点其它子树
那么在链上的路径形态也比较容易刻画,小 A 走到一个子树里面然后 小 B 封锁这个点根链上所有点的出度,再放 小 A 出来
注意如果在根链之前的点上选择过封锁边了,钻进这个子树的代价要累加
预处理出来度数前缀和 / \(s\to t\) 所有点非链上子树的代价,考虑二分答案
检查当前答案是否合法的时候从 \(s\) 到 \(t\) 找所有能钻的地方,计算 小 A 是不是钻进去就使次数非法,是则需要提前删除该子树
如果必须删除子树的操作大于 \(s\) 到该点的距离,那么该 \(mid\) 不合法
时间复杂度 \(\Theta(n\log n)\)
欢乐豆
由于 \(a_i>0\),所以对于没有修改出边的点,直接走完全图上的初始边就是最优的,不需要进行松弛
为了实现方便,将所有边修改涉及的点都叫做弱联通块里面的点
对于那些存在被修改的边的点,观察这种点 \(u\) 到其他点的最短路的可能构成
-
到弱联通块里面的点有走出弱联通块再返回/直接在弱联通块里面走两种选择
-
到弱联通块外面的点可以花费 \(a_u\) 的代价走到弱联通块外面的点 \(v\),再花费 \(a_v\) 的代价随便走;也可能在弱联通块里面乱走,走到一个比较优的 \(w\) 点走出去
注意这里的 \(a_v\) 一定是取的最小的 \(a_v\)
将弱联通块里面的点给一个标号,由于朴素堆优化 Dijkstra 复杂度有边的瓶颈,在完全图有非常大的缺点,那么考虑线段树优化寻找从源点开始最小距离点的过程
对于每个弱联通块里面的点都进行一个 Dijkstra,初始化叶子上每个点距离为走出再走回的最小距离
每次松弛操作可以转化为单点取 \(\min\) 和对被修改的两点之间的区间取 \(\min\) ,是线段树的基础操作
在计算弱联通块里面的点的最短路的时候维护 \(dis_x+a_x\) 的最小值来表示走出弱联通块时候的最短路即可
时间复杂度 \(\Theta(m^2\log m)\)
混乱邪恶
将 \(n\) 变成偶数,即若 \(n\) 不是偶数就在序列里面补一个 \(0\),然后排序
设 \(d_i=a_{2i}-a_{2i-1}\),不难发现 \(\sum d_i\le m-\frac{n}2\le n\),目标是让 \(\sum d_i=0\)
尝试推导是否存在任意解,不难发现方法是对 \(d_i\) 的正负号进行调整,同时过程中满足 \(\forall\ d_i\ge 0\)
尝试归纳证明这个有解的结论:设 \(n\le 2k\) 时有解,那么现需要观察 \(n=2k+2\) 时的情况
这时可以找到不为 \(0\) \(\min d_i\) 和 \(\max d_i\) 并将这两组合并,也就是说得到 \(\min d_i\) 的一组内的 \(c_i\) 一律取反,发现 \(d_i\) 之和的变化量是 \(2\min d_i\)
这样子 \(n\leftarrow n-1\),变成了原来的子问题,根据归纳假设,原命题成立
回到代码实现直接能取反就取反就行了,比说的简单多了
仙人掌
观察邻接矩阵行列式的实际含义:找到两个点匹配,每次贡献 \(-1\) 的逆序对数
注意每指定两个数匹配的时候行列式必然加一,而图为仙人掌的时候将整张环进行匹配的逆序对数为环长减一
这是因为可以将环上的数字重新排序并标号,让 \(p=\rm{\{len,1,2,\dots,len-1}\}\) 注意到交换两个点标号之后等价于交换一行的同时交换一列,这样子逆序对数正负性不变
同时环上匹配的时候可以钦定两个方向所以贡献要乘二
梳理贡献之后是一个套路的仙人掌 \(\rm{DP}\),当然这种东西不容易想出,建出圆方树后分开讨论:
定义实点,也就是原仙人掌上的点有 \(f_{x,0/1}\) 表示这个点是不是被匹配了,匹配指作为 \(p_i\) 出现,对于新建出来的虚点表示 \(f_{x,0/1}\) 表示点双的根是不是被匹配
由于在现行圆方树上虚实点交替出现,对于实点的转移直接考虑是不是在这个点双被选中,\(f_{x,0}\) 则是所有儿子 \(f_{t,0}\) 的乘积
对于虚点而言,需要一个子 \(dp\),注意在环上第一个点和最后一个点的时候计入环顶被选的方案,同时计算 \(f_{t,0}\) 的乘积来维护环上全选的贡献
合并实点的时候两两一组,做一个子 \(\rm{DP}\) 即可得到答案
乘法
关注到十六进制的后十六位可以使用自然溢出保存,同时可以在 \(\Theta(\log)\) 的时间内计算 \(n!\) 中有几个因子 \(2\),对 \(4\) 取余后左移回来即可
偶数的部分可以先左移再计算,本质上是一个子问题,那么问题转化为:\(1\to n\) 中奇数的乘积之和,写作下式
由于是在 \(\bmod 2^{64}\) 意义下计算,那么选择 \(2i\) 的项不能超过 \(63\) 个,否则直接溢出
枚举选择了多少个 \(2i\),将 \(2\) 因子最后左移加入答案,此时就是计算在 \(n\) 里面选择 \(m\) 个数字的乘积,求所有选择方案的和
直接写出该问题的暴力 \(\rm{Dp}\) 转移式子发现是 \(2m\) 多项式,直接平方 \(\rm{Lagrange}\) 插值就可以做到 \(\Theta(T\log^{4}m)\),也可以少一个 \(\log\) (但是前者过了后者没过去是怎么回事呀)
而其实这个问题的答案使用第一类斯特林数可以表示成:
原因是在斯特林数的递推过程中,增加环大小的那些数字 \(x\)(区别于增加环数量的数字)会贡献 \(x-1\),将 \(n\leftarrow n+1\) 后就可以得到正确和式
根据实际含义,环大小不为 \(1\) 的环非常少,可以 \(\rm{DP}\) 求出:设 \(dp_{i,j}\) 表示使用 \(i\) 个数字组成 \(j\) 个大小大于 \(i\) 的环,转移是相对简单的,枚举枚举添加圆排列中的数字个数
实现的时候细节是计算逆元,偶数不存在逆元,奇数的逆元是其 \(2^{63}-1\) 次方,直接使用欧拉定理可以得到
斐波
先记录比内公式:
记 \(\phi_1 = \frac{1+\sqrt 5}2,\phi_2=\frac{1-\sqrt 5}2\)使用该公式可以将单个 \(f(S)\) 进行展开:
稍加以 \(\rm{GenFunc}\) 思想就能知道 \(\sum\limits_{T\subset S} \phi^{\sum\limits_{x\in T} x}=-1+\prod_{x\in S} (\phi^x+1)\)
也可以组合意义理解:从每个中选一个,也可以不选,最后减去空集情况
至此本题得到极大简化,那么可以对于每个 \(x\) 计算 \(\phi_1^x,\phi_1^x\phi_2^x\) 的值,因为比内公式本身使用无理数表示有理数,那么无理部分必然消成 \(0\),那么可以不维护 \(\phi_2^x\)(来减小常数因子对程序运行效率的影响)
回到本题,注意题目并不是求一个 \(f(S)\) 的值,而是求一个区间的子区间作为 \(S\) 时的 \(f(S)\) 值之和,这是一个简单的 \(\rm{DS}\) 问题,可以离线套用古老的序列问题的解法,也可以考虑用如下的线段树做法:
线段树每个节点维护 \(\rm{ans,Mult,lsum,rsum}\) 表示答案,区间权值乘积,区间内每个前缀的的乘积和,每个后缀的乘积和,合并信息自推不难
实现的时候可以使用 \(a\sqrt 5+b\) 的形式维护复数值,记得重载乘法和不同复数不同之处
百鸽笼
将对空格子等概论变成随便找,找到空格子位置为止,此时每列被选中的概率是 \(\frac 1n\),但因为空格子相对于总数量的比例是确定的,两者相乘得到的结果与前者相同
设 \(G_i(x)=\sum\limits_{i<a_i} \frac{x^i}{i!}\),观察最后得到的序列的形态(不妨设最终是第 \(k\) 列有剩余格子):
这时候序列中出现的 \(y\neq k\) 的 \(y\) 的数量不小于 \(a_y\) 个,\(k\) 的数量恰好为 \(a_k-1\) 个
如果枚举最终序列长度不简洁,但是 \(e\) 的展开式能让式子大为简化,写出序列的 \(\rm{EGF}\) 和用 \(\rm{EGF}\) 表示的答案
这里 \(i\) 枚举的是除去最后一个人得到的序列长度,上面的 \(i!\) 是多重集排列在使用 \(\rm{EGF}\) 时必要的补充项,分数线下的 \(n^{i+1}\) 是对应的概率,因为序列长度是 \(i+1\),指数含义也由此得到
展开答案,可以表示成 \([e^ax^b]\) 的系数和 \(e^ax^b\) 的乘积的和,其中系数可以通过 \(\rm{DP}\) 得到,设为 \(\lambda\)
推导单独一个 \([e^ax^b]\) 对答案的贡献:
后半部分由 \(\sum_{k\ge 0}\binom{m+k}{k}x^k=\frac{1}{(1-x)^{m+1}}\) 可以直接化简,至此题目得到 \(\Theta(n^6)\) 的做法,正常写法都可以通过
但是仍然可以通过先做背包求出所有列对应的多项式系数再在单独求的时候消除贡献(类回退背包状物)将复杂度降至 \(\Theta(n^5)\)
游戏
分析两人策略能得到:
-
对于先手而言,如果他想达到这个石子被/不被自己拿走的目的,在该目的达成/最终失败之前,他的目的保持不变,具体而言,如果某时想投一面,那么一直投一面
-
对于后手而言,如果先手想达到石子被/不被自己拿走,后手为胜利则需要抗拒先手决策,那么先手想拿走,后手要抢,先手弃的子,后手也不能要
据此定义 \(A_i\) 表示还剩 \(i\) 个石子时先手执先时先手胜利概率,\(B_i\) 表示还剩下 \(i\) 个石子时,后手执先时先手胜率,转移为:
设每个石子没有在两次投硬币内拿走的概率是 \(R\)
- \(A_i\le B_i\) 时,先手在第 \(i+1\) 个石子的决策应为拿走该石子,此时 \(R=(1-p)(1-q)\)
使用等比数列求和均可以简单求出,观察转移之后的 \(A_i-B_i\),化简后有 \(pqA_i-pqB_i\ge 0\),成功变成了下面的情况
- \(A_i\ge B_i\) 时,先手在第 \(i+1\) 个石子的决策是放弃该石子,此时 \(R=pq\)
再观察得到 \(A_i-B_i\le 0\),那么需要用第一种转移的式子
两种转移交替进行,直接使用矩阵快速幂优化即可
Sanrd
不难发现序列的一个 \(\rm{LIS}\) 和一个 \(\rm{LDS}\) 的交点不超过 \(1\) 个,设 \(f_i\) 表示经过 \(i\) 的 \(\rm{LDS}\) 个数,总 \(\rm{LDS}\) 个数为 \(\rm{all}\)
如果一个 \(\rm{LIS}=\{p_1\dots p_k\}\) 满足 \(\sum_{i=1}^k f_{p_i} =\rm{all}\) 那么其跨过所有 \(\rm{LDS}\)
那么可以在求 \(\rm{LIS}\) 的过程中记录两个当前 \(f\) 之和的值不同的前驱,因为后面转移过程中带来的增量是相同的,所以必有其一合法
仍然使用数据结构优化这个寻找 \(\rm{LIS}\) 的过程,对于 \(f_i\) 非常大的事实,直接让其对大质数取模
关注较大方案存在性常用的手段便是对大质数取模,该技巧也可以运用到一类回退背包问题的解决中
如何优雅地送分
观察 \(2^{f[i]}\) 这一奇怪统计方式,不难发现是一个数集合状物,那么问题直接转化为求解下式:
考虑展开 \(\mu^2(i)=\sum\limits_{k^2|i} \mu(k)\),证明考虑实际含义,将 \(\mu\) 函数值不为 \(0\) 的因子放在集合中便可以看做一个完整的容斥起手式
提出 \(k\) 就非常优美了,记 \(S(n)=\sum\limits_{i=1}^n\lfloor \frac ni \rfloor\)
直接整除分块就行了
ARC124E
传出球数最小值不为零时可以将所有人的传球数量减少,因为得到的 \(\{B\}\) 序列不变
观察原式的实际含义:得到序列后从每个人手上选出一个球的方案数
每个人的球只有两种来源:自己原来没有传出去的球/上一个人传过来的球。启示我们记录球的来源以 \(\rm{DP}\)
下设 \(S_k(n)=\sum\limits_{i=1}^n i^k\)
状态定义有点奇怪:\(dp_{i,0}\) 表示第 \(i\) 个人从自己处选择球且不计第 \(i\) 个人选择方案时前 \(i-1\) 个人的选球方案数,\(dp_{i,1}\) 表示第 \(i\) 个人从前面人选择球且计入第 \(i\) 个人选球方案时的方案数
转移分为 \(4\) 种情况:
-
\((i,0)\to (i+1,0)\) 第 \(i\) 个人的选择方案需要被计入,因为下一个人在自己处选择,所以没有 \(a_i\),剩下几个球就有几个方案,系数为 \(\sum\limits_{i=1}^{a_i} i=S_1(a_i)\)
-
\((i,0)\to (i+1,1)\) 有两个人没有计算,且都在 \(a_i\) 中选择:\(\sum\limits_{i=1}^{a_i-1} i(a_i-i)=S_1(a_i)a_i-S_2(a_i)\)
-
\((i,1)\to (i+1,0)\) 需要计 \(a_i\) 个球中有几个传出,系数是 \(\sum\limits_{i=0}^{a_i}1=1+a_i\)
-
\((i,1)\to (i+1,1)\),和第一个情况类似,系数是 \(\sum\limits_{i=1}^{a_i} i=S_1(a_k)\)
因为是一个环,那么需要在 \(1\) 处统计答案,这时可以枚举 \(1\) 的决策是在自己处选择还是在 \(n\) 个人出选择
注意这样子统计出来的并不要求传球数最小为 \(0\) 那么可以再编一个传球数最小为 \(1\) 的式子写出来即可
CF1086F
设 \(f_i\) 表示 \(i\) 权值对应点数,对其做前缀和得到 \(g(i)\),观察其实际含义得到 \(g_i\) 表示在 \(i\) 时刻被标记点数
至此答案可以被表示成 $ T g_T-\sum_{i=0}^{T-1} g_i$
在每个两个点构成的正方形交之前,点数可以表示成一个二次函数,而在正方形交之后点数扩展量仍逐时间递增,也是二次函数
所以我们发现 \(g_i\) 是分段二次函数,每个点值都是矩形面积并,可以简单求出,剩下的任务是分段求出二次函数并求和即可
时间复杂度 \(\Theta(n^3\log n)\)