test20230914

写在前面的话

今天考试没有挂分,考场的时候自认为思考得还算投入。希望以后考试的时候对于每一道题目都能有自己深度的思考。

今天考场估分 \(100+80+100+30=310\) , 实际得分 \(100+80+100+30=310,\text{rank2}\)

看了一下考试的题解啊,发现自己还是有一些知识点和小 \(\text{trick}\) 不知道的,所以等到 \(\text{CSP-S}\) 之后, \(\text{NOIp}\) 之前小补一下。

今天考场的时候我吸取了之前考试的教训,选择了一个相对合适的开题顺序。我的开题顺序 \(T3-T1-T4-T2\) ,在考后进过仔细评估认为最优开题顺序应该是 \(T1-T3-T4-T2\)

\(T1\)

题目描述

现在有一个 \(n\) 节点的数,边有边权。我们定义两点之间的拒了为最短路径上的最小边权

现在希望给这个树选择一个根,使得根节点到其余节点的距离之和最大,输出这个距离之和。

\(n \leqslant 10^6\)

思路点拨

不知道为什么,感觉题面上写满了并查集。我们可以稍稍往这个方面去思考。

考虑一条边在什么时候会成为最大值,我们将全部的边按照边权从大到小排序,再加入并查集的时候我们判断一下边的两边节点的集合,设为 \(S1,S2\) 。如果根在 \(S1\) 里头,那么他到每一个 \(S2\) 的点的距离就是这条边的边权(因为没有加入并查集的边的边权更小),我们给 \(S1\) 的每一个点加上 \(|S2|\times v\) ;同理,每一个在 \(S2\) 的根到达 \(S1\) 的节点的距离都是这条边的边权,所以在 \(S2\) 的点加上 \(|S1|\times v\) 。之后合并两个并查集。

现在我们需要给一些树里的点做加法,还需要合并一些树,难道需要什么科技吗?不需要啊,因为最后每一个节点的点权就是以该节点为根的答案,所以我们的查询是离线的。我们考虑在并查集里头打标记,使用类似于 \(\text{Kruskal}\) 重构树的方式合并+路径压缩。时间复杂度 \(O(n \log n)\)

代码实现比较简单,这里不贴了。

\(T2\)

题目描述

image

对于 \(80 \%\) 的数据,\(n \leqslant 500 , k \leqslant 10\)

对于 \(100 \%\) 的数据, \(n \leqslant 500, k \leqslant 60\)

思路点拨

考虑我们按照编码一位一位的填。定义状态 \(dp_{l,r}\) 表示区间 \(l,r\) 这个子问题的最小 频率 \(\times\) 码长 。答案要求 \(dp_{1,n}\) 。我们再定义 \(sum_i\) 表示频率的前缀和数组。

因为要求字典序有序,所以我们的目前考虑的区间 \([l,r]\) 的每一个数的编码最低位所形成的序列必须是单调不降的,我们可以将这个区间划分成 \(c(1 <c \leqslant k)\) 段,第 \(i\) 段的最低位就填 \(i\) ,之后就被我们划分成了更小规模的问题,这也符合动态规划的标志。因为要将一个区间划分成若干段,所以我们可以设计一个子序列提取动态规划。

我们定义 \(f_{i,j}\) 表示对于上述区间 \(l,r\) ,我们考虑到下标 \(i\) ,目前是第 \(j\) 段的一个最小贡献。那么转移是比较显然的:

\[f_{i,j}=\min\{f_{mid,j-1}+dp_{mid+1,i}\} \]

单轮是 \(O(n^2k)\) ,因为一共有 \(O(n^2)\) 个区间,所以我们考虑对于区间的长度从小到大进行一个转移,时间复杂度 \(O(n^4k)\) 。但是我们注意到,这个 \(f\) 数组的转移十分浪费,因为同一个左端点完全只需要做一遍。所以我们按照左端点从大到小,右端点从小到大的顺序转移,依然可以使得我们在转移 \(dp_{l,r}\) 的时候,\(l<p<q<r\)\(dp_{p,q}\) 的函数值已经被计算出来了。所以我们的时间复杂度就优化到了 \(O(n^3k)\) 。因为同一个左端点只需要做一次 \(f\) 数组的动态规划。

之后,我们既然计算出了 \(f\) 数组,\(dp_{l,r}=\max\{f_{r,i}\}+(sum_r-sum_{l-1})\) ,因为我们在区间填了一层编码,所以贡献加上区间和。这个不是时间复杂度的瓶颈,目前可以通过 \(80\) 分。

但是运用计算机强大的计算能力,我们发现 \(dp\) 数组是满足四边形不等式的,所以 \(f\) 数组的计算可以使用决策单调性优化,时间复杂度 \(O(n^2k \log n)\) ,可以通过 \(100\) 分。

代码实现比较简单,不贴了。

\(T3\)

题目描述

现在给出了一个正奇数 \(n\) ,希望找到一个 \(x \leqslant 10^{18}\) ,使得 \(x-\phi (x) =n\)

\(n \leqslant 10^9\)

思路点拨

对于一个 \(x\) ,我们考虑对其使用质因数分解来更好的计算 \(x-\phi(x)\) ,本质上来说,这就是与 \(x\) 有公因子并且比 \(x\) 小的数的个数。

我们考虑最为简单的情况就是 \(x=pq\) ,其中 \(p,q\) 都是质数,那么 \(x-\phi(x)=\dfrac{pq}{p}-\dfrac{pq}{q}+\dfrac{pq}{pq}=p+q-1=n\) ,我们简单移相发现 \(n+1=p+q\) ,因为 \(n\) 是一个正奇数,所以 \(n+1\) 就是一个偶数。也就是说,如果一个偶数我们可以快速分解为两个不相同质数的和,那么我们就可以求出 \(x=pq\)

想一想,将一个偶数划分为两个不同质数的和不就是哥德巴赫猜想吗?这个在 \(1e9\) 范围内肯定是正确的。问题又来了,怎么拆分成两个质数和和呢?其实 \(n+1=p+q\)\(\min\{p,q\} \leqslant 10^4\) ,这个可以打表证明。所以我们可以枚举其中较小的质数,暴力判断 \(n+1-q\) 是不是质数,时间是可以通过的。

值得注意的是,\(n\) 在比较小的时候不满足哥德巴赫猜想,所以可以暴力。

代码比较简单就不贴了。

\(T4\)

题目描述

现在有一个 \(n\) 和节点 \(m\) 条边的简单无向图。想要求出全部导出子图中有多少个边的数量是偶数。

\(n \leqslant 46\)

思路点拨

这个数据范围比较折半。。。

但是两个子图的答案本身就不好合并,加上偶数的限制就更难了。假设一个导出子图的边是 \(c\) 条,那么我们认为它的权值就是 \(\dfrac{1+(-1)^c}{2}\) ,这个是等价的。现在我们只需要求出全部导出子图的权值和就可以了。

现在我们按照编号奇偶性将点分为两半之后考虑,我们假设这是左部和右部。我们枚举一个左部的点集 \(S\) 并且算出他自身的贡献,那么对于一个右部的点 \(x\) 如果个 \(S\) 的点有奇数条连边,那么它的贡献就是 \(-1\) ,不然我们当什么都没有发生。我们称与集合 \(S\) 连边为奇数的右部点集合为 \(\mu(S)\)

我们定义 \(f_S\) 表示 \(mu(A)=S\) 的集合 \(A\) 的权值和, \(g_S\) 表示右部子集 \(S\) 的权值。答案就是

\[\sum f_Ag_B(-1)^{A \cap B} \]

我们使用 \(\text{FWT}\) 优化,时间复杂度 \(O(n 2^{\frac{n}{2}})\)

posted @ 2023-09-14 13:57  Diavolo-Kuang  阅读(20)  评论(0编辑  收藏  举报