集训D11总结
模拟赛总结
T1
题意
\(k\) 个大小为 \(s_i\) 的连通块 , 用 \(k-1\) 条边联通 , 设 \(d_i\) 为第 \(i\) 个连通块的度数 ( 只考虑连的 \(k-1\) 条边 ) . 每种连边方案的权值为 \(\prod\limits_i d_i\) , 求所有方案的权值和 .
题解
这个性质看一眼就能联想到经典的图联通方案数 . 形式是 :
其证明来源于 prüfer 序列 . 考虑用一种用边联通方案的基础上 , 每个连通块情况是与连通块大小有关的 . 考虑枚举度数 .
总度数是 \(2k-2\) , 为了得出在指定度数时的方案数 , 可以用 prüfer 序列 , 加 \(k\) 条边 , 则表示这 \(k\) 条边的序列长度为 \(k-2\) , 每个连通块内点出现次数是 \(d_i-1\) . 连通块内部总共有 \(s^{d_i}\) 种情况 . 即 :
为了化简这个形式 , 应用多项式定理 , 需要换元 \(t_i=d_i-1\) .则 :
发现这个公式的推导过程和度数紧密相连 .
这道题方案本身有权值 , 不能套结论 , 但是权值与度数有关 , 考虑回到枚举度数那一步 , 要求的就是 :
在这个式子基础上 , 直接转向对度数做背包 ( 对 prufer 序列 dp 侧重于研究形态 , 不适合这道题 ) .
首先把这个多重集排列数拆了 , 发现能消掉一些东西 :
\((k-2)!\) 单独提出来做系数 , 剩下的部分可以背包 . 总度数为 \(2k-2\) , 设 \(f_{i,j}\) 为考虑到第 \(i\) 个连通块 , 已经用了 \(j\) 个度数时的权值 , 转移为 :
这个背包是 \(n^3\) 复杂度的 , 可以拿到 40 分 .
考虑优化 , 看起来类似前缀和优化比较有前途 , 考虑快速转移 . 先考虑 \(s_i=1\) 的部分分 , 可以得到启发 :
从前一个到后一个除了插入了 $f_{i-1,j} $ 这一点外 , 相当于整体 \(k\to k+1\) , 可以维护 \(sum=\sum \limits _{k=1}^{j} f_{i-1,j-k}\) , 实现快速转移 .
再考虑一般情况 , 发现没有本质区别 , 每次更新时多需要 \(\times s_i\) 一次 , 用同样方法维护即可 .
总结
比较基础的一道题 , 只要知道 prufer 这个事情基本上就能把 \(n^3\) 写出来 , 然后几乎可以很确定正解是在这个基础上优化 , 又因为转移是多项式的 , 想到类前缀和优化 , 这个问题就解决了 . 甚至可以转 FFT , 也能解决 .
但是被卡常了 , 其实很没道理 , 本来常数不应该特别大 . 为了正确性稳妥就没写 \(\frac{1}{2}\)常数 . 事实说明还是在稳妥前提下上满优化比较好 .
T2
题意
把排列 \(A\) 划分成两个非空排列 \(B\) , \(C\) , 最大化 \(B\) 前缀最大值和 \(C\) 前缀最小值的和 .
题解
直接从考场最后半个小时突然想通的地方开始考虑 .
考虑这个问题类似于找出两条不交的上升子序列和下降子序列 , 但是是有去别的 . 区别在于这里每个元素必须放进去 .
考虑向前者转化 , 在一些情况下 , 可以通过把元素放入某条序列使得它不对当前局面产生任何影响 . 称递增序列为 \(B\) , 递减序列为 \(C\) , 当前元素在 \(C\) 上方可以放入 \(C\) , 在 \(B\) 下方可以放入 \(B\) . 因此只有它在 \(B,C\) 中间位置时肯定会对当前状态产生影响 .
到这里发现已经有一个子问题解决了 !
根据刚才的分析 , 只要 \(B,C\) 之间交叉 , 就可以任意地选择一个元素是否放入 \(B/C\) 或者等效于不放 , 因此如果遇到了交点 , 可以直接通过预处理倒序的上升/下降子序列得出答案 .
因此问题剩下前一半 : 如何维护 \(B,C\) 不交的情况 ?
显然这一部分中难办的是夹在 \(B,C\) 中间的元素 , 无论放在 \(B/C\) 都必然会改变 \(B/C\) 的值域 . 利用这一特点 , 可以发现考虑到 \(i\) 时且尚未相交时 , \(B,C\) 事实上划分了 \([1,i]\) 里元素的值域 , 中间存在元素是不合法的 , 因此可行的 \(B/C\) 只有 $O(值域) $ 种 , 枚举每一种情况 , 都是可以对 \(B,C\) 分别统计方案数的 , 可以获得 \(O(n^2)\) 做法 .
考虑优化 , 发现值域上维护的信息在每次加入新元素时改变并不大 , 考虑用数据结构维护每一段上的信息 . 具体地 , 维护每一段在 \([1,i]\) 已经选中的 \(ans\) , 左端点对应在 \([i+1,n]\) 上的最长上升子序列 , 右端点对应在 \([i+1,n]\) 上的最长下降子序列 . 这里都可以用线段树维护 , 考虑 \(i\) 动时维护的上升/下降子序列会有影响 , 可以直接把每个值对应的后缀序列挂在线段树点上 , 每个点的贡献就是线段树的一个前缀/后缀 , 可以在查询时处理 .
总结
在 11:30 时突然从向原序列找两条子序列这里获得了启发 , 思路推到了 \(n^2\) 这里 , 并且大致意识到了应该数据结构维护是可行的 , 但是写不完 , 还是保了一下 \(n^3\) . 场后发现这个思路几乎和题解思路重合 , 但是写的时候很艰难 , 这种处理区间信息的边界问题太多了 .
似乎有更加易于实现的思路 .
思路还是在场上生成出来了 , 但是慢了一步 . 同时是从一个发散的处理无用点的角度出发的 . 事实上是尝试转化时探出了正确的思路 . 场上积极转化意义确实非常重大 , 不可能所有题一开始的转化就切中正确方法 , 关键是足够发散 , 启发性地向有可能解决问题的方向探索 . 还要重点抓住通过研究得到的接近**本质 **, 简洁 , 明确的思路 .
T3
题意
设数列 \(P=\{1,1,2,2,2,3,3,3,3,4,4,4,4,4\cdots\}\) , 其中 \(i\) 出现 \(i+1\) 次 . 设数列 \(Q\) 为 :
\(T\) 次求 \(Q(n)\) , \(T\le10^4,n\le10^{40}\) .
题解
首先有一个 \(n\le10^{10}\) 的部分分是理应拿到的 , 同时只有这一部分不会超出 __int128 .
前 20 分 , \(10^7\) 的部分可以直接打表 .
对 \(10^{10}\) , 考虑 \(P(n)=O(\sqrt n)\) , 优先想办法向根号方向优化 , 发现 \(P(i)\) 相同的一段相当于是等差数列 , 抓住这一点 , 可以考虑暴力跳段 , 每段的数值可以 \(O(1)\) 计算 , 单次复杂度根号 .
进一步优化 , 可以预处理每一段首项 , 每次二分出来在哪一个段 , 配合打出来的 \(10^7\) 的表就可以了 .
考虑正解 , 显然单纯根号不合适 , 这时需要一些稳定 decreasing 的方案 .
仍然从 \(P(i)\) 有效值只有 \(\sqrt n\) 种出发 , 构造 \(Q(P(i))-Q(P(i-1))\) 的形式来缩减有效计算量 . 意义是这样构造可以通过转化式子维持连续 \(Q(i)\) 的形式 , 同时缩小规模 :
其中 \(f^0=1,F^0=x\) , 是构造出来的辅助函数 .
后半部分可以化为 :
前后两部分都得到了我们想要的 , 把规模化到了 \(P(n)\) , 同时保证了 \(Q(P(i))\) 这个形式不变 .
为了向下递归 , 定义 \(f^d=F^{d-1}(\frac{i(i+1)}{2}-1)\) , 这样向后递归的部分也可以类似地处理了 .
大约层数为 \(4\) 时 , 规模就很小了 , 可以直接计算 . 多项式用插值算 . 需要高精 .
总结
从实用以及自己水平来讲 , 能稳定保证 40 分 , 而且不浪费过多时间更重要 . 显然 \(10^{10}\) 是分水岭 , 前半部分是 \(\sqrt n\) 可行的部分 , 可以通过预处理等等简单解决 , 而后部分必然需要decrease递归 , 没有思路的前提下确实应该跳 .
看懂题解做法后 , 感觉构造还是比较巧妙 , 但是理解不了这种思路如何生成 , 不透彻 . 或许是值得以后回顾的题 .