加载中...

牛客寒假基础算法训练营4(ADFGJL)

A

期望计算 + 推公式

首先,由期望的线性性可知和式的期望等于和式中每一项的期望之和。因此求\(\sum_{i=2}^{n}|a[i-1]-a[i]|\)的期望,等价于求每一个\(|a[i-1]-a[i]|\)的期望,再求和。所以问题转化为求\(|a[i-1]-a[i]|\)的期望,其中\(a[i]\)\([l_{i},r_{i}]\)内等概率取值。

易得:

\[E(X) = \frac{\sum_{a_{i-1}=l_{i-1}}^{r_{i-1}}\sum_{a_{i}=l_{i}}^{r_{i}}|a[i - 1] - a[i]|}{(r_{i-1}-l_{i-1}+1)*(r_{i}-l_{i}+1)} \]

考虑怎样用一个关于\(l_{i-1},l_{i},r_{i-1},r_{i}\)的公式直接得到分子的值:

两个区间的交并关系只有三种:

  1. 相互分离 -> 这个容易得到
  2. 相互包含 -> 可以拆为 两对相互分离 和 一对相同线段重合
  3. 相交 -> 也可以拆为 两对相互分离 和 一对相同线段重合

于是等价于求 两条线段相互分离 和 两条相同的线段重合 这两种情况的分子和式,通过推公式可以得到解。具体见代码。

code

D

思维题 + 贪心

首先短字符串中能与长字符串中字符匹配就要尽可能贪心匹配,这样能保证答案不会更差。

对于匹配上的一对字符,可以作为回文串的外侧。这样就只需要考虑回文串内部的匹配即可。

这样问题就变为:给定一个字符集合,每次操作可以修改一个字符,使得该字符集合可形成回文串的最小修改次数。

考虑回文串:长度为偶数时,字符集合可形成回文串的充要条件为所有字符数量均为偶数;同理长度为偶数时,充要条件为只有一种字符数量为奇数,其余均为偶数。

可见需要尽可能减少奇数数量字符的种类数。最优方案即为每次修改一个奇数字符为另一个奇数字符,这样每一次操作都可以将两种奇数字符变为两种偶数字符,贪心操作即可。

code

F

二分 + 双指针

求第 \(k\) 大可以二分来求——看\((a[i] + a[j]) mod p >= mid\) 的数量是否 \(>=k\) 即可。乍一看有模 \(p\),序列内的单调性不确定。实际上将每个 \(a[i]\)均模 \(p\)后,\((a[i] + a[j]) mod p >= mid\) 的情况只有两种:

  1. \(mid <= a[i] + a[j] <= p - 1\)
  2. \(p + mid <= a[i] + a[j] <= 2 p - 1\)

这是由模 \(p\)\(a[i] + a[j] <= 2p\) 这一关键性质决定的。因此将序列模 \(p\) 后再升序排序,对于每个 \(a[i]\),通过两次二分就可以直接确定\((a[i] + a[j]) mod p >= mid\)\((i, j)\)对数量,进而以 \(O(nlognlogV)\)的复杂度确定第 \(k\) 大。

找到 \((a[i] + a[j]) mod p\) 的第 \(k\) 大后,前 \(k-1\) 大的数量不会超过 \(k\),可以直接暴力求得。

注意不能直接把所有前 \(k\) 大求出,因为数量并不确定(只知道第 \(k\) 大,并不知道第 \(k\) 大有多少个,可能 \(>=k\) 的数量是 \(O(n^{2})\)级别的),而要先将所有 \(k-1\) 大求出(能保证它们的数量是 \(<k\)的),额外记录第 \(k\) 大的数量,再看总数是否超过 \(k\) 即可。这样能保证复杂度控制在 \(O(k)\),具体细节见代码。

code

G

主席树

这里换一个与 \(F\) 不同的思路:即用堆维护每个 \(i\),当前未输出的最大值,这样就能保证每一次堆顶一定是当前所需要的最大值。

则问题转化为:求对某个 \(i\),且 \(j \in [l_{i}, r_{i}]\)\((a[i] + a[j]) \space mod \space p\) 未输出过的最大值。

\((a[i] + a[j]) \space mod \space p <= 2p\) 这一关键性质,可以发现只需要找以下二者的最大值:

  1. \(<p-a[i]\) 的最大值
  2. \(>=p-a[i],<2p\) 的最大值,即整体的最大值

求2很简单,只需要求区间最大值即可。而求1可以用主席树——先查询 \(a[l_{i},r_{i}]\)\([1,p-a[i]-1]\) 的数量,即 \(p-a[i]-1\) 在其中的排名,设为\(r\),则 \(mx1\) 即为 \(rth\)。求\(mx2\),即查询区间最大值,也可以转化为求主席树的第 \(k\) 小。类似于归并排序的思想,可以动态维护好对于某个 \(i\) 的前 \(x\) 大值,所有 \(i\) 用一个大根堆维护即可。具体细节见代码。

code

J

一道思路很好想但代码较难写的图论题

处理出每个联通块的 \(size\) 和包含的最小结点编号,根据 \(k\) 与联通块个数 \(cntg\) 的大小关系,分两种情况讨论:

  1. \(k<=cntg\):部署数不充足,只能挑选前 \(k\) 大的联通块部署。为保证字典序最小,每个联通块部署的肯定是编号最小的结点,然后可以先处理出每个联通块的字典序最小方案(\(bfs\) + 优先队列),再用优先列处理每个联通块的方案,保证最终构造序列的字典序最小即可。这是我的做法,比较麻烦,实际上不需要处理每个联通块的字典序最小方案,将所有初始点放进一个优先队列里,同时对多个联通块做一次\(BFS\)即可。

  2. \(k>cntg\):部署数有剩余,显然可以部署到所有联通块,但盈余的部署数需要服务于字典序最小。可以贪心地考虑:在剩余部署数\(>\)未部署的联通块个数时,可以直接部署当前未在序列中的编号最小的结点,当然如果可以通过在当前序列中的点直达,就不需要浪费部署次数,直接加入序列即可。从\(now=1\)开始贪心地按顺序考虑,直到剩余部署次数\(=\)未部署联通块个数时,某个前缀\(1到now\)一定是序列的前缀。再对\(now+1到n\)继续采用1的思路即可。(代码写得比较麻烦qwq...)

code

L

典题

题目:对于两个数组\([a,b]\),要做到给定\(\forall\) 查询区间\([l,r]\),快速求出:

\[ \sum_{i=l}^{r}\sum_{j=i}^{r}a[i]\oplus b[j] \]

这种题首先一定要想到拆位,将每个二进制位的贡献分开计算,最后求和。

如果题目改为求:

\[ \sum_{i=l}^{r}\sum_{j=l}^{r}a[i]\oplus b[j] \]

那么问题就变得很简单了—— 对于第\(i\)个二进制位,贡献只来自于不同数字\((0和1)\)相异或。所以该位的贡献为:

\[ 2^{i} * cnt1 * cnt0 \]

其中\(cnt1\)\(a[l到r]\)内第\(i\)位为\(1\)的元素个数,证明略。

而两式区别在于\(j=l\)改为了\(j=i\),那么该怎么做呢?

可以\(O(n)\)预处理出每个后缀的答案(即固定 \(r=n\),对每个 \(l\) 求一遍答案),设为\(sufans[l]\)

那么对于\([l,r]\)\(ans=\)

\[ sufans[l] - sufans[r + 1] - \sum_{j=0}^{30}(numa0*numb1 + numa1*numb0) \]

\(numa1\)\(a[l,r]\)中第 \(j\) 位为 \(1\) 的元素个数
\(numa0\)\(a[l,r]\)中第 \(j\) 位为 \(0\) 的元素个数
\(numb1\)\(b[r+1,n]\)中第 \(j\) 位为 \(1\) 的元素个数
\(numb0\)\(b[r+1,n]\)中第 \(j\) 位为 \(0\) 的元素个数

证明:模拟一下即可

code

posted @ 2025-02-16 09:08  jxs123  阅读(32)  评论(0)    收藏  举报