杂题选讲

1. CF487C Prefix Product Sequence

#构造 #数列 #乘法逆元

简要题意

是否存在一个长度为 \(n\) 的排列,使得其前缀积在\(\mod n\) 意义下两两不同?
如果存在,输出 \(YES\) 并且换行输出一个构造的排列;
如果不存在,输出 \(NO\)
\(1\le n\le 10^5\)

思路

首先判断对于每个 \(n\) 是否有解。

我们可以发现对于 4 和质数 总是有解的,而对于其它数总是无解的,因为对于其它数,一定有多个小于它的且不同的数的乘积为它的倍数,而这是前缀积,这样就会有多个前缀积 \(\mod n\) 后为 \(0\) 。也不能把它们放在最后,因为 \(n\) 在前面也会发生同样的情况。

然后考虑如何进行构造,首先 \(1\) 应该在最前,因为它放在后面会使两个前缀积相等,\(n\) 应该在最后,理由在判断是否时已经说了。

中间我们可以用一个特殊的方法 \(\frac{2}{1} \ ,\ \frac{3}{2} \ ,\ \frac{4}{3} \ ,\ ... \ ,\ \frac{n}{n-1}\) ,这样前缀积数组就会是 \(1,2,3,4,5,...,0\),然后求分母的逆元即可。

然后我们来证明中间的数是否可能相等,即在 \(\mod n\) 意义下存在 \(\frac{i+1}{i}=\frac{j+1}{j} \ (1\le i\lt j\lt n)\)

\[\begin{eqnarray} &\frac{i+1}{i}=\frac{j+1}{j} \ (1\le i\lt j\lt n) \\ \Rightarrow &(i+1)\times j=(j+1)\times i \\ \Rightarrow &i\times j+j=i\times j+i \\ \Rightarrow &i=j \end{eqnarray} \]

\(i\lt j\) 矛盾,所以中间的数不可能相等,完成。

时间复杂度 \(O(n\log_2 n)\)\(O(n)\)(线性递推逆元的话)

2. CF1406E Deleting Numbers

#交互题 #构造 #唯一分解定理

简要题意

在一个序列里存在整数 \(1\) ~ \(n \ (1\le n\le 10^5)\)。有一个特殊的数\(x \ (1\le x\le n)\) 你需要找出这个数,你有三种操作。

\(A \ a\) 表示询问序列中为 \(a\) 的倍数的数的个数。
\(B \ a\) 表示询问序列中为 \(a\) 的倍数的数的个数并删除它们 \(x不会被删除\)
\(C \ a\) 表示答案为 \(a\)

你可以询问不超过 \(10^4\) 次,确定 \(x\) 是什么。

思路

根据唯一分解定理,如果我们知道 \(x\) 的所有质因子,我们就可以通过操作 \(B\) 枚举质因子的幂次来快速求出 \(x\)

因为 \(2*3*5*7*11*13*17=510510\) 所以 \(x\) 最多有 \(6\) 个不同的质因子 ,\(2^{17}=131072\) ,所以 \(x\) 的质因子幂次不会超过 \(16\)

所以我们如果知道 \(x\) 的质因子有哪些,就可以用不超过 \(16\) 次的次数求解出 \(x\)

那么我们如何找出 \(x\) 的所有质因子呢?

暴力的做法是对于每一个质数都先进行一次 \(B\) 操作,再进行一次 \(A\) 操作如果还能够找到数说明这就是 \(x\) 的质因子。

\(10^5\) 内的质数一共有 \(9600\) 多个,每个都这样做就有接近 \(20000\) 次,不符合题目要求,所以我们考虑如何减少查询次数。

我们发现严重的浪费出现在 \(A\) 操作上,考虑是否可以代替。

我们发现如果前面都使用 \(B\) 操作的话,那么不考虑 \(x\) ,每个质数进行 \(B\) 操作时删除的个数是一定的(每个数都是被它的最小质因子删除的),那么如果个数与预处理的不一样,就说明出现了 \(x\),此时将这个质数记录下来即可。

但是我们如果这样做的话会有一个问题,那就是我们无法知道 \(x\) 的最小质因子,因为那是 \(x\) 第一次被删,于是我们需要单独求出 \(x\) 的最小质因子,我们现在还剩大概 \(300\) 次操作。

考虑如何判断 \(x\) 的最小质因子是否出现,用 \(A \ 1\) 可以求出当前序列中还剩多少个数,记录一下应该删除了多少个数,如果与剩下的数的个数加起来不为 \(n\) 说明 \(x\) 的最小质因子已经出现,此时对之前筛过的质数每个进行一次 \(A\) 操作即可找出 \(x\) 的最小质因子,那么消耗的次数是 块数+块长 的,此时,将块长取到 \(\sqrt{cnt} \ (cnt 为质数个数)\) 最优。

总消耗次数大概为 \(cnt+2\times \sqrt{cnt}+16\) 次,不会超过 \(10^4\)
时间复杂度 \(O(n+cnt)\)

3. CF521D shop

#贪心

简要题意

一个长度为 \(n\) 的序列 \(A\),你有 \(m\) 个操作,每个形如 \(t,i,b\)

\(t=1\) 表示将 \(A_i\) 赋值为 \(b\)\(t=2\) 表示将 \(A_i\) 赋值为 \(A_i+b\)\(t=3\) 表示将 \(A_i\) 赋值为 \(A_i\times b\)

你需要选择最多 \(k\) 个操作,并按一定顺序进行使得 \(\prod_{i=1}^{n} A_i\) 值最大。

输出你选择了多少个操作并且按操作顺序输出你选择的操作编号。

\(1\le n\le 10^5,1\le k\le m\le 10^5\)

思路

首先我们发现,如果只有 \(t=3\) 的操作,直接排序,贪心的选择最大的 \(k\) 个即可。

然后我们考虑如何扩展到加法和赋值操作上。

假定我们已经选好了 \(k\) 个操作,如何操作使得最终值最大,对于每个 \(A_i\) 的操作,我们一定是先赋值,再加,最后乘可以让它最大。

而对于每个 \(A_i\) 的加法,我们一定是按照从大往小进行选择的,所以我们选择对于 \(A_i\) 的第 \(j\) 个加法的前提就是前 \(j-1\) 个加法均已被选择,那么我们就可以知道选择第 \(j\) 个加法时,当前 \(A_i\) 的值为多少,那么对于每个加法,我们均可以将它改写为乘法的形式,如 \(a+b\Rightarrow a\times \frac{a+b}{a}\)。那么我们就可以将其放入乘法的序列中进行贪心的选择。

最后我们剩下一个赋值操作,我们肯定最多对每个数赋值一次且是选择最大的数进行赋值,那么我们只需保留对于每个 \(A_i\) 最大的赋值操作,并且由于我们的赋值操作是在最初进行的,所以本质上是将 \(A_i\) 加上一个数,我们可以将它改写成加法,如 \(a\to b \Rightarrow a+(a-b)\),直接扔进加法操作种排序即可。

到此我们已经完成了加法和赋值操作的转换,直接贪心的选前 \(k\) 个即可。

这里记录一下思考时遇到的一个小问题,就是我们要求的是赋值操作在最开始进行,而将它变成加法排序后,它不一定是最大的加法也就是它不一定第一个操作,那么我们还可以保证算法的正确性吗?

答案是可以的,因为最后转为乘法后可以打乱操作顺序,我们仍可以将赋值操作提到第一个进行操作,举个栗子。

设原数为 \(x\) 赋值操作为 \(x\to y\),有加法操作 \(z_1 \ge z_2\ge ...\ge z_a \ge y-x \ge z_{a+1}\ge z_{a+2} \ge ...\ge z_b\)

那么我们最终转为乘法操作的乘积为 \(\frac{y+\sum_{i=1}^b z_i}{x}\),无论怎么改变顺序答案不变。

4. CF1481F AB Tree

#多重背包DP

简要题意

一棵 \(n\) 个节点的树,你需要往 \(x\) 个节点上的填一种字符,往剩下 \(n-x\) 个节点上的另一个字符,每个节点的字符串为根到它路径上节点的字符所组成的字符串。
问你如何填字符,使得 \(n\) 个节点的不同字符串的数量最少。

\(1\le n\le 10^5,0\le x\le n\)

思路

首先我们很明显可以发现答案至少为树的高度。
此时把我们树按高度进行分层,考虑最优策略如何让答案为树的高度。

可以发现每一层的节点都会被给到相同的字符。

但这需要有几层的 \(size\) 之和为其中一种字符的数量,我们不可能每次都遇上这种条件,这只是答案的下界。

所以考虑没有几层的 \(size\) 之和为其中一种字符的数量时,我们应该怎么办。

题目中子节点的字符由父节点进行提供,那么一旦其中一层有孩子的节点所拥有的字符不同,那么它传下去之后会让答案以几何倍数增长。

我们贪心的想,肯定优先满足这些有孩子的节点,而一棵树中同一层有孩子的节点只会有 \(\lfloor \frac{n}{2} \rfloor\) 个,完全可以满足。

具体的,现在已经填好了第 \(i\) 层,准备填 \(i+1\) 层,未填节点一共有 \(size\) 个,会有孩子的节点最多有 \(\lfloor \frac{size}{2} \rfloor\) 个,\(a,b\) 中一定有一个剩余数量 \(\ge \lfloor \frac{size}{2} \rfloor\),所以可以先把非叶子节点赋上相同的字符,如果可以覆盖整层就覆盖。

覆盖不了就说明有一种字符已经被用完,用另一种字符赋给剩下所有节点,不会给再造成任何额外的贡献,那么只有这一层叶子节点与非叶子节点不同,答案增加 \(1\),所以答案上界为树高加 \(1\)

判断用背包DP(装入对象为每层 \(size\))解决。
然而,\(n\le 10^5\),朴素的01背包会T飞,考虑对DP进行优化。
我们可以发现每层 \(size\) 会有大量重复,可以用多重背包二进制优化进行求解。
分析时间复杂度,发现最劣情况下,\((1+2+3+4+5+...+x)=\frac{x(x+1)}{2}=n\)\(x\)\(\sqrt n\) 级,有 \(x\) 个物品,所以它的时间复杂度最劣大概是 \(O(n \sqrt n )\) ;
题目还要要求输出方案,在 DP 过程中记录决策方案,在记录有多少大小为 \(x\) 的层,进行染色。

5. CF878E Numbers on the blackboard

#贪心

简要题意

一个长度为 \(n\) 的序列 \(a\),你每次可以选择 \(\forall i(1\le i\lt n)\)\(a_i\)\(a_{i+1}\) 变为 \(a_i+2\times a_{i+1}\),注意是删除 \(a_i\)\(a_{i+1}\) 后在它们原有的位置中插入一个数。
\(q\) 次询问,每次问 \(l_i\)\(r_i\) 的数能组成的最大值,对 \(10^9+7\) 取模。

\(1\le n,q\le 10^5,-10^9\le a_i\le 10^9,1\le l_i\le r_i\le n\)

思路

我们发现只有两种不同的操作方式,从左往右合并一段区间和从右往左合并一段区间。
分别考虑两种方式对答案的贡献。

从左往右
对于形容 \(x_1,x_2,x_3,...,x_{len}\) 的序列每次选择开头的数与后一个数合并,最后对答案的贡献就是 $$1\times x_1+\sum_{i=2}^{len} 2\times x_i$$
从右往左
对于形容 \(x_1,x_2,x_3,...,x_{len}\) 的序列每次选择末尾的数与前一个数合并,最后对答案的贡献就是 $$\sum_{i=1}^{len} 2^{i-1} \times x_i$$
于是我们发现原序列中的每个数最后对答案的贡献为 \(2^k (1\le k\lt n)\) 次,贪心的考虑让正数的系数尽可能的大,负数的系数尽可能小,而我们发现从左往右的合并方式只能用于合并 \(len\) 个数,没有办法进行贪心,所以我们考虑先从右往左将原序列合并成若干个块,最后从左往右合并为一个数。

而从右往左将原序列合并成若干个块的过程中,对于一个块中的数有 \(k_i=k_{i-1}+1 (k_1=0)\)

一个明显的贪心是遇到正数就将它加入已有块,遇到负数就单独开一个块储存,但是一个简单的样例即可卡掉这个贪心,如 \(11,11,11,-3,11\) 最优的应该是将它分为 \(1\) 块,而这个贪心策略会把它分成\(3\) 块,我们考虑为什么会出现这种情况。

发现只要当前块贡献是正数,就可以向前一个块合并,因为这样这个块的贡献就被放大了 \(2^{l}\)\(l\) 为前一个块的块长,而前一个块的系数并没有改变无论是正数还是负数,且它就算是合并到了第一个块没有了最后从左往右合并的 \(2\) 的倍数,因为 \(l\ge 1\),这是不劣的。所以我们有了一个贪心策略,如果当前块贡献为正,向前合并直到贡献为负或只剩一个块。

这里需要注意一下,如果序列是全正数,合并几次就会到达 long long 上限,而我们发现每个块最小为 \(-10^9\)(就是 \(a_i\) 最小的情况,不与其它块合并。而我们合并每个块是将后一个块 \(\times 2^l\) 加上前一个块,而 \(l\) 最小是 \(1\),所以如果一个块的大小超过了 \(10^9\),它就一定可以合并到第一个块,直接赋值为 \(+ \infty\),计算时特判即可。

那么现在我们将原始的序列合并为了若干个块,需要用从左往右的方式将它合并为 \(1\) 个块,然而,我们每次询问 \(l_i\)~\(r_i\) 并不一定是整块,需要单独处理左右的散块,可以将询问离线下来,按 \(r_i\) 从小到大排序,每次处理到 \(r_i\),中间的整块和右边的散块用前缀和优化一下,左边的散块单独拆开,可以用类似 \(hash\) 提取字段和的方式提取一个后缀,不要忘了中间的整块和右边的散块合并时有一个而的倍数。

时间复杂度 \(O(n\log_2 n)\)

posted @ 2024-12-09 21:45  Qing_Nian  阅读(21)  评论(0)    收藏  举报