2017山东一轮集训 [14/20]

感觉题目质量挺好的, noi前最后挣扎一下
没做完就afo了。停更

Day1 Set

题目大意:
\(n\le 10^5\) 个非负整数, 要求把它划分成 \(x_1, x_2\), 使得 \(x_1\oplus x_2\) 最大的前提下求最小的 \(x_1\)

算法:
想清楚再写....
令所有数的异或和为 \(S\). 则是要求 \(x+(S\oplus x)\) 最大
写一写位运算表, 当 \(S_i = 1\)\(x_i\) 取什么对结果没有影响
因此我们将 \(S_i=0\) 的位作为关键位. 按照关键位从高到低插线性基即可做出第一问
第二问的话, 我们在插入线性基的时候先考虑关键位, 都弄完之后从高到低插非关键位即可

Day2 Pair

题目大意:
\(m\le n\le 10^5\) 的两个序列 \(B,A\), 问有多少个 \(A\) 的子区间与 \(B\) 匹配.
定义匹配为: 存在一种 \(B\) 的排序, 使得对应位相加都不小于给定阈值

算法1: 本题
\(B' = max(0, lim - B)\) , 然后对 \(B'\) 排序
根据贪心, \(B'\) 大的配上 \(A\) 大的
我们需要保证对于每个 \(B\), 比它大的 \(A\) 的数量 要多于 比它大的 \(B\) 的数量
线段树动态维护即可

算法2:\(i\) 个物品在 \(\ge t_i\) 的时刻才能被选择, 求最早选完时间
先把物品 \(i\) 堆在时刻 \(t_i\) 上. 这样形成了一个柱状统计图
然后从左往右推倒, 往右挤
答案是 \(max(i + suffixsum[i])\)

算法3: HNOI2018 转盘
差不多的贪心思路. 这题最后变成维护 \(min(i + suffixmax[i])\)
那种pushup要一个log的方法维护即可

Day2 Shadow

题目大意: 三维空间. 给定光源, 凸多面体, 一个平面. 求该凸多面体在那个平面上阴影的面积

算法:
在平面上取两个不共线的向量 \(a, x\)
\(cross(a, x)\) 求出平面法向量 \(v\)
\(cross(v, x)\) 求出与 \(x\) 垂直的, 平面上的向量 \(y\)
\(x, y\) 标准化 (变成单位向量) 后成为正交基
将凸多面体的投影点跟这两基求投影. 即可转为二维凸包的问题.
问题转为求射线和面的交点. 分别求出光源和射线与平面法向量的投影长度比一比即可
\(cross = (yz-zy, zx-xz, xy-yx)\) , 垂直两个向量, 符合右手法则. 长度=面积

Day3 第一题

题目大意:\(n\le 5000\) 根直的木棍中选出 \(6\) 根能拼成正方形的方案数

**算法: ** 只有(1+1+1+3), (1+1+2+2)两类情况. 大力容斥.

Day3 第三题

题目大意:
给定 \(n\le 60000\) 次多项式, 要在 \(\bmod 10^6+3\) 意义下多点求值
要求的点为 \(x_0\cdots x_n\), 满足 \(x_k = bc^{4k} + dc^{2k} + e\)

算法1: 本题
先考虑平凡的 \(b, c, d\)
先代入得 \(f(x_k) = \sum_{i=0}^n a_i b^i (c^{4k} + \frac d b c^{2k} + \frac e b)^i\)
配方, 令 \(u = \frac d {2b}, v = \frac e b - u^2\), 得 \(f(x_k) = \sum_{i=0}^n a'_i ((c^{2k}+u)^2 + v)^i\)
大力展开得 \(f(x_k) = \sum_{i=0}^n a'_i \sum_{j=0}^i \binom i j v^{i-j} \sum_{l=0}^{2j} \binom {2j} l u^{2j-l} c^{2kl}\)
通过卷积可以转为这样的问题 \(F(k) = \sum_{i=0}^{n} a_i c^{2ki}\)
写成 \(F(k) c^{k^2+i^2-(k-i)^2} a_i\) 就可以卷积做了.
要特判 \(b, c, d\) 的非平凡情况

算法2: 任意模数FFT
之前是死记的. 最近找到了比较好的理解方式. 写一写
令 小写字母表示 实数 列向量
\(F\) 为 单位根的范德蒙德矩阵
\(\overline A\) 表示把矩阵 \(A\) 的每个元素取 \(conj\)
\(a'\) 为 将 \(a\) 的非 \(0\) 项部分 reverse 的结果

根据单位根乘法为在复平面旋转的性质, \(\overline F a = (F a)'\)
这样 \(IDFT\) 就好些多了. \(F^{-1} a = \overline F a / n = (Fa)' / n\).

考虑 \(\overline{F(a+ib)} = \overline {Fa} + \overline{iFb}\)
考虑几何意义 \(conj\) 是上下翻转, 乘 \(i\) 是逆时针转 \(90°\). 先逆时针转 \(90°\) 再翻 = 先翻再顺时针转 \(90°\)
那么原式为 \(\overline Fa -i \overline F b = (Fa)' - i (Fb)'\)
配合 \(F(a+ib) = Fa + i Fb\). 我们可以一次 \(FFT\) 求出两个 \(DFT\)

Day5 字符串

题目大意: 给定字符串 \(s_1\cdots s_n\) , 求有多少个本质不同的 \(t\), 使得 \(t\) 可以写成 \(sub_1+\cdots+sub_n\)

算法: 每个串建后缀自动机, 然后对 \(n\) 个字符串跑类似序列自动机一样的贪心.

Day5 苹果树

题目大意:
有坏苹果和好苹果共 \(40\) 个, 好苹果有美味度
连成树时, 树的权值定义为与至少一个好苹果相邻的好苹果的美味度之和
求美味度 \(\le lim\) 的树的个数.

算法:
考虑把苹果分成三类, 坏苹果, 不贡献美味度的苹果. 贡献美味度的苹果
对于一种方案, 可以将这三类苹果内部进行任意交换.
所以我们可以给这三类苹果标号为 \([1..A], [A+1..B],[B+1..C]\)
这样就只跟不贡献美味度的苹果个数有关了 (\(A, C\) 均已知)
接着问题变为两个 :

  1. 对于每个 \(B\), 求出满足条件的树的个数
  2. \(2^{40}\) 种方案种, 统计出美味度和满足条件的方案里面, 不贡献美味度的苹果分别有多少个
    问题2) 折半 + two-pointer 即可
    问题1) Matrix-tree + 容斥 :
    \(f[i]\) 表示连边时让 \(i\) 个点只与坏苹果连边, 其他随意时跑出的生成树个数
    这样会包含 \(j \ge i\) 的方案. 由于带标号, 被附上容斥系数 \(\binom {n-i} {j-i}\)
    要算恰好 \(k\) 个不贡献美味度的苹果时, 容斥系数需要满足

\[[j=k] = \sum_{i\le j} \binom {n-i}{j-i} coef[i] \]

打表得 \(coef[i] = (-1)^{i-k} \binom {n-k}{i-k}\)

Day5 距离

题目大意: 给你一棵树和一个排列. 每次询问一条树上路径对应的排列序列中的所有点到某个点的距离.

算法1:
考虑维护每个点到根路径上的排列序列的虚树. 使用二进制分组
可持久化二进制分组, 资磁后插后删.
实现是: 当右儿子满且左儿子未build时build左儿子. 这样插入删除复杂度势能分析一下就对了
询问的话因为每个点右儿子都未build, 所以区间查询时每个完整区间都要额外的 \(O(\log)\) 的深度
复杂度就欢快 \(O(\log^2)\) 再乘虚树了, 居然过了

其实是写完才发现的...实现跟原本设计的算法出了点偏差...
其实应该是 当一个段满时如果它左边的段未build就build它左边的段.
这样查询才是真 \(O(\log)\).
左边的段可能并不是左儿子. 还有走一条链过去? 注意到这种情况只会出现一次. 出现时特判一下 log走过去就好了
还有一个常数的优化是: build时并不新开一个点. 因为build只是优化询问复杂度, 不影响结构, 直接在原树上改即可

算法2:
点分 + 可持久化线段树 \(O(n\log^2)\)

算法3:
边分治 + 直接对分治树可持久化 \(O(n\log)\)

算法4:
好像直接 树剖 + 可持久化线段树就可以了. \(O(n\log^2)\)
分成到根路径上的点, 和有LCA的点两类.
树剖维护虚边信息那样做就好了

Day6 重建

题目大意:
\(n\le 1000\) 个点 \(m\le 10000\) 条边的图, 给定源汇和关键点集合.
求最大的一个 \(c\ge 0\) 使得将所有边权增加 \(c\) 后, 源汇间最短路 = 源汇间只经过关键点的最短路

算法:
\(c \to \infty\) 时, 点数越少越优.
\(f_i\) 表示走 \(i\) 步到达汇点的最短路. \(g_i\) 表示只经过关键点的...
考虑枚举经过关键点的点数 \(i\). 那么能够限制 \(c\) 的只有 \(j<i\)\(f_j\)
这些限制下取到的最大 \(c\), 如果 \(c<0\) 则不ok
否则, 我们需要判断是否存在 \(\Delta \in [0, c]\) , 满足 \(\forall j\ge i\) 都有 \(f_j+j\Delta \ge g_i + i\Delta\)
注意到点数少的路径, \(c\) 越大越优. 只需check \(\Delta = c\) 即可
复杂度 \(O(n(n+m) + n^2)\)

Day7 基因

题目大意: 强制在线区间本质不同回文串数. \(n,m\le 10^5\)

算法1: 本题, \(O(n\log^2 n)\)
右端点从左往右扫, 维护每个左端点的答案
根据回文串的性质, 对于某个左端点的答案, 在右端点右移时最多增加 \(1\), 新增的只会是区间内最长回文后缀
先扫一遍原串把回文树建好, 在fail树的dfn序上用线段树维护每个回文串的最后一次出现位置
暴力做法是扫描每个以 \(r\) 结尾的回文串, 将 [其最后一次出现位置的左端点+1, 新左端点] 的答案加 \(1\)
根据回文串boarder-series的性质, 我这里对每段等差数列只考虑 \([lef, rig)\)
\(lef\) 开始缩, 在 \(rig\) 之前缩的长度是不会超过原串一半的.
此时如果缩后的串的最后一次出现位置的左端点不是缩之前的那里, 就会产生更小的公差, 矛盾
因此我们可以成段更新. 每段开头重新到线段树里找last即可
用可持久化线段树维护左端点答案即可

算法2: 本题离线版, \(O(n\sqrt n)\)
先建好回文树然后带撤销莫队即可 (分块)

算法3: 区间回文串数 \(O(n\log n)\)
跑马拉车然后将询问区间拆成前后两半统计
求的东西形如 \(\sum \min (hw[i], i-l)\) , 两边同时减 \(i\) 最后补回即可
注意去掉那些以马拉车新增字符为边界的回文串

Day6 子序列

题目大意: 求区间本质不同子序列个数. \(n\le 10^5, 字符集(m)=10\)

分析:
考虑暴力的做法, 从左往右加字符
\(f_i\) 表示最后一个字符为 \(i\) 的方案数, 当 \(i=m+1\) 时表示空串
每次要么你贪心选 \(f'_{newchar} = \sum f_i\), 要么不选 \(f'_{other} = f_{other}\)
类似这样 :
\(\begin{bmatrix}1&&\\1&1&1\\&&1\\\end{bmatrix} \begin{bmatrix}f_0\\f_1\\f_2\end{bmatrix} = \begin{bmatrix}f'_0\\f'_{newchar}\\f'_2\end{bmatrix}\)

算法:
求一下逆矩阵, 唯一区别是把非对角线上的元素取了负号 (变的只有 \(newchar\) 那行)
\(U = \begin{bmatrix}1&\cdots&1&0\end{bmatrix}\), \(V = \begin{bmatrix}0\\\vdots\\0\\1\end{bmatrix}\)
记转移矩阵为 \(A\)
那么答案就是 \(UA_{l-1}^{-1}\cdots A_1^{-1} A_1 \cdots A_r V\) . 两边分别坐前缀和即可
(1)考虑左乘逆元, 实际上是把 \(newchar\) 所在行减掉其他行.
维护矩阵的同时维护每列的和即可 \(O(m)\) 维护
(2)考虑右乘转移矩阵, 实际上是把 \(newchar\) 所在列加到其他列.
维护矩阵的同事每行维护一个修改标记, 标记打打矩阵改改就可以 \(O(m)\) 维护
(3)考虑左乘 \(U\) 的意义, 实际上是求某一列去掉最下面那个数的和. 这正好在矩阵里维护了, 可以 \(O(m)\)
(4)考虑右乘 \(V\) 的意义, 实际上是把矩阵的最后一列搬出来. 可以 \(O(m)\)
(5)考虑询问, 一个行向量乘一个列向量是 \(O(m)\)
这样就 \(O((n+q)m)\) 通过了此题

Day7 逆序对

题目大意: \(n, m\le 10^5\) 求长度为 \(n\) 的排列中, 逆序对个数为 \(m\) 的有多少个.

分析:
从大到小决定把每个数插在哪里, 这样能确定每个数对逆序对的贡献
\(i\) 个数可以贡献的范围是 \([0, i-1]\)
写成生成函数, 因为是求单项, 等比数列分子分母分开做, 最后 \(O(n)\) 卷积即可
分母是 \(\frac 1{(1-x)^n}\), 这个就是 \(\sum_{i\ge 0} \binom{i+n-1}{n-1}x^i\)
分子是 \(\prod_{i>1} (1-x^i)\). 一个类似拆分数的dp. 见下述 算法1

算法1: 用不重复的数组成 \(m\)
显然被选的数最多根号个, 据此优化 \(dp\)
\(f[v][s]\) 表示选了 \(v\) 个数, 和为 \(s\) 的方案数. 转移时考虑 \(1\) 选不选, 然后其他数整体减一
\(f[v][s] = f[v][s-v] + f[v-1][s-1-(v-1)]\)
如果选择的数有上限 \(n\) 的话
注意到上式如果之前一直是合法的, 那么转移后非法只会是出现 \(n+1\), 将违法情况一出现就销毁掉即可
\(f[v][s]\) -= \(f[v-1][s-(n+1)]\)

算法2: 用可重复的数去组成 \(m\)
我们可以分段 \(dp\), 最后两段卷积起来.
\(B = \sqrt m\)
权值 \(< B\) 的分一段, 直接用完全背包
权值 \(\ge B\) 的分一段, 类似 算法1 的做, 转移时考虑 \(B\) 选不选. 不同的是选了\(B\) 时不全体减一
\(f[v][s] = f[v][s-v] + f[v-1][s-B]\)
选择的数有上限的话, 像算法1那样处理就好了

扩展:
\(m < n\) 时, 分子在 \(m\) 以内有值的地方就是是五边形数了, 有值的地方只有根号个
因此可以出到 \(m < n \le 10^{12}\), \(\mod \approx 10^6\) 的样子
要做一下 \(lucas\) 定理, 预处理 \(mod\) 以内的阶乘, 复杂度是 \(O(\sqrt m) + O(mod)\)

Day6 三元组

题目大意: \(A,B,C\le 10^5\)\((A,B,C)\) 以内的三元组中两两互质的有多少个

算法1: 2018集训队互测, 蒜头的奖杯
这题的题意是给你 \(6\) 个长度为 \(n \le 10^5\) 的序列 \(A-F\), 求 $$\sum_{i=1}^n \sum_{j=1}^n \sum_{k=1}^n A_i B_j C_k D_{(i,j)} E_{(i,k)} F_{(j,k)}$$
先枚举 \(i\) 然后暴力反演把 \((i,j), (i,k)\) 去掉. 写成下式. (其中 \(D', E', F'\) 表示莫反后的序列)

\[\sum_{i=1}^n A_i \sum_{a|i} D'_a \sum_{b|i} E'_b \sum_{a|j} \sum_{b|k} B_j C_k \sum_{d|(j,k)} F'_d \]

前面有冗余枚举, 转为枚举gcd(lcm). 将 \(A\) 对其倍数求和变成 \(A'\). 写成下式

\[\sum_{g=1}^n \sum_{ab\le \lfloor \frac n g\rfloor} D'_{ga} E'_{gb} A'_{gab} \sum_{a|j} \sum_{b|k} B_{gj} C_{gk} \sum_{d|(j,k)} F'_{gd} \]

\(a\le b\) 为例. \(b\lt a\) 同理. 将后半部转换求和顺序 \(\sum_{b|k} C_{gk} \sum_{d|k} F'_{gd} \sum_{d|j} [a|j] B_{gj}\)
因为 \(a\) 只有根号 \(\sqrt {\frac n q}\) 种, 每种 \(O(\frac n g \log\log)\) 预处理. (预处理方法见 算法3)
复杂度是上面那个的积分. 由于收敛, 复杂度是 \(O(n^{1.5} \log\log)\)

算法2: SDOI2018 旧试题
\(\sigma_0(ijk)\) 写成 \(\sum_{a|i}\sum_{b|j}\sum_{c|k} [a,b,c 两两互质]\). 套用上述做法即可

算法3: Comment Ants的调和数
利用高维前缀和的方法可以解决部分两函数卷积的问题
一个序列卷一个完全积性函数是很容易做的. 比如说求因子位置的和, 反过来也可以求倍数和.
对于不完全积性函数, 目前 \(\mu\) 是可以的. 高维前缀和时从大到小, 让每个质数仅能作用一次即可

Day7 养猫

题目大意: 任意长度为 \(k\) 的子区间里都要有 \([L, R]\) 天睡觉. 吃饭睡觉各有愉悦值. 问最大愉悦值, 并输出方案

算法:
先全选吃, 然后再该睡. 写成变量列出等式, 相邻项相减再并保留第一条原式, 按流量平衡建出费用流的图.
根据变量所在边的流量确定方案

posted @ 2018-07-03 15:25  _zwl  阅读(375)  评论(0编辑  收藏  举报