HEOI2021考前乱看题解
浅薄的理解,仅供娱乐。
[CQOI2009]中位数
题意
给一个排列,求中位数为 \(b\) 的长度为奇数的连续子序列个数。(\(n <= 10^5\))
题解
不要想的太复杂,发现只关心数的相对大小,所以可以抽象为 \(-1, 0, 1\),然后就是求子序列和为 \(0\) 的序列个数,这个直接向左扫一遍,向右扫一遍然后用map记一下就可以了。
[SHOI2001]小狗散步
题解
因为题意太难抽象,所以就直接写题解了,一道网络流建模好题,关键是容易让人想到最短路等等,其实看看数据范围确实发现可以是二分图匹配,把所有距离小于关键点的点连边,跑二分图匹配就可以了,因为dinic解决二分图匹配的复杂度是 \(O(m\sqrt n)\),所以数据范围可能出的不会很小,需要特殊考虑。
[NOI2001] 食物链
题意
A 吃 B,B 吃 C,C 吃 A,给若干句话,判断真假。
题解
扩展域并查集,把每个点扩展为 \(x_{self}\),\(x_{eat}\),\(x_{enemy}\),分别表示 \(x\) 的同类,食物和天敌,最后合并同类就可以了,需要注意的是如果 \(x\;eat\;y\),那么 \(x\) 的天敌是 \(y\) 的食物,需要考虑全面。
[JSOI2016]最佳团体
题意
给一颗树,选 \(i\) 就必须选 \(fa[i]\),每个点有 \(c[i]\) 和 \(w[i]\),求一个合法的点集,使得 \(sumc\) 和 \(sumw\) 的比值最大。
题解
涉及到比值,也就只能用 01分数规划 了,然后发现这道题就变成了求一个合法的最大值,直接树上背包就可以了,复杂度 \(O(n^2logn)\)。
分数规划的柿子:\(\sum_{i=1}^k c[i] - ans \times w[i] <= 0\)
[SHOI2011]双倍回文
题意
给定一个字符串,求最长双回文串。(\(n \leq 10^6\))
题解
这里给出两种做法:
-
manacher
考虑到本质不同的回文串的级别是 \(O(n)\) 的,所以我们在做 manacher 的过程中,每次暴力更新就可以了,具体做法是每次从当前的右端点暴力扩展,这样的复杂度是对的。 -
回文自动机
直接预处理一个 \(trans[i]\) 数组表示长度不大于 \(len[i] / 2\) 最长回文后缀,这个处理可能需要一些细节,然后建完后直接扫一遍就可以了。
[SCOI2008]城堡
题意
给定一个 \(n\) 个点的图,让你选择 \(k\) 个点,使一个点到你选择的点的最小距离最小。(\(n <= 50\))
题解
这道题主要是用于模拟退火的做法,可以发现这是一个序列,那么我们退火的过程就变化为了随机枚举两个位置进行交换,然后大概就可以过了。
一般模拟退火主要用于求解最优方案,且对于一个方案计算其答案的复杂度不太高时使用。
[AHOI2018初中组]分组
题意
给一个序列,要求你选出若干序列,使得每个序列的权值连续且不出现重复权值,问你最短的序列最长是多少。
题解
很好的贪心,显然每次尽可能的取是不对的,我们用数组 \(c[i]\) 表示 \(i\) 这个位置出现的次数,那么如果 \(c[i] <= c[i+1]\), 那么我们可以继续取,否则我们就停止这次的选取,开始新的一次,这样的贪心显然是对的。
[TJOI2018]游园会
题意
一个串只能有 'N''O''I' 三种字符,给一个长度为\(n(n<=15)\) 的模式串,让你求有多少个长度为 \(m(m<=1000)\) 的串,满足 LCS 为 \(k\),且不能出现 "NOI" 这个字串的方案数。
题解
主要用到了DP套DP的思想,我们发现对于一个固定的串,LCS是单调不降的,而且模式串的长度只有 15,所以我们定义 \(f[i][j][k]\) 表示填到了第 \(i\) 个字符,当前模式串被匹配的状态为 \(j\),且这次填的字符为 \(k\) 的方案数,我们需要解决状态 \(j\) 的后继转移节点状态问题(\(tips\):DP套DP解决的一般都是状态不好转移的情况),所以我们再设一个 \(nxt[i][j]\) 表示当前状态为 \(i\),且这次填第 \(j\) 个字符所能转移到的状态,然后这道题就解决了。
斐波那契数列
题意
求斐波那契数列的循环节(\(mod <= 2^{32}\))
题解
本题有两种做法。
-
做法一
首先分解质因子,然后对于 \(p^k\) 求循环节,答案就是 \(\text{lcm}\)。
考虑怎么求 \(p^k\) 的循环节,首先有个结论 \(G(p^k) = G(p) \times p^{k-1}\),其中 \(G(x)\) 表示 \(\bmod x\) 的循环节,然后给出对于 \(p > 5\) 的循环节结论:\(p \bmod 5 == (1,4),G(p) = p-1\),\(p \bmod 5 == (2,3),G(p) =2p-2\),然后这题就随便做了。 -
做法二
首先猜测循环节不会大于 \(6 \times mod\),事实确实如此,然后有个东西叫做生日悖论,所以我们直接随机个几百次,每次放到 Hash 表里查询就行了,是不是非常简单,感觉实用性很高。
[TJOI2012]炸弹
题意
二维平面内有 \(n\) 个点,每个点可以连到与其的曼哈顿距离为 \(r\) 的点,且满足传递闭包,求至少需要几个初始点,才能连到所有的点。(\(n <= 10^5\))
题解
暴力建图并查集是 \(n^2\) 的,所以我们还是考虑优化建图,这次的优化建图方式是扫描线加平衡树优化建图。
我们发现每个点的作用范围是个正方形,所以可以构建一条扫描线,我们的本意是想用扫描线使其一维满足条件,然后这个点向另外一维距离离它最近的两个点连边,这样每个点只用连两条边,是 \(O(n)\) 的,并且这样是正确的,因为需要维护最近的两个点,所以需要用平衡树维护。
[SNOI2017]炸弹
题意
平面上有 \(n\) 个点,每个点可以连到 \([l_i, r_i]\) 的点,且有传递闭包性质,求每个点能连到多少个点。(\(n <= 10^5\))
题解
不难看出是个Tarjan了,不过边数达到了 \(O(n^2)\) 级别,发现本题的连边范围是一段区间,所以可以线段树优化建图。
线段树优化建图就是建 \(nlogn\) 个点,然后在这些点中连边,是的点数和边数都达到 \(nlogn\) 级别。
考虑缩点后的做法,直接求并不是很好求,所以我们考虑维护出每个点的所能扩展到的最左和最右,然后遍历一遍 DAG 就可以了。
[Ynoi2019 模拟赛] Yuno loves sqrt technology III
题意
强制在线,维护区间众数。(\(n,m <= 10^5\))
题解
复杂度 \(O(n\sqrt n)\),考虑分块,首先预处理出任意两个块之间的答案,这个部分的复杂度可以 \(O(n\sqrt n)\) 预处理,然后我们还需要用 vector 存下每个权值的所有位置,然后定义数组 \(pos[i]\) 表示 \(i\) 这个下标所在的 vector 里的位置,到此为止预处理完毕。
考虑一段询问 \([l, r]\),我们先以 \([bel_l+1, bel_r-1]\) 的答案作为答案,然后分别往左扫和往右扫,如果对于当前的一个位置满足 \(vec[pos[i]+ans] <= r\) 那么可以更新答案,单次复杂度 \(O(\sqrt n)\)。
当然如果可以离线的话,我们当然可以用回滚莫队了。
【模板】莫队二次离线(第十四分块(前体))
题意
给定一个序列,多组询问,每次求 \([l, r]\) 内的 \(popcount(a_i \;\text{xor}\; a_j) == k(i < j)\) 的个数。(\(n, m <= 10^5\))
题解
发现可以离线,于是莫队,但是发现每次指针移动的贡献不是很好搞,所以考虑再次离线预处理出每次转移的贡献,我们设处理一次指针移动的复杂度是 \(O(k)\),那么复杂度可以从原来的 \(O(nk\sqrt n)\) 优化到 \(O(nk + n\sqrt n)\)。
现在只考虑从区间 \([l, r]\) 移动到 \([l, r+1]\),发现答案需要加上 \((r+1, [l, r])\) 的贡献,这个因为满足可减性,所以可以变成 \((r+1, [1, r]) - (r+1, [1, l])\),发现前面的部分可以 \(O(nk)\) 预处理,后面的那个可以用莫队做到 \(O(n\sqrt n)\) 预处理,然后再跑一遍莫队就可以得到答案了。
对于预处理我们使用扫描线,我们可以利用异或的交换律来解决问题,定义 \(c[i]\) 为权值为 \(i\) 的异或后为 \(k\) 的个数,那么每次更新时只需要 \(++c[a[i]\; \text{xor}\;x]\),其中 \(x\) 的 \(popcount\) 为 \(k\) 。
[Ynoi2019 模拟赛] Yuno loves sqrt technology II
题意
求区间逆序对。(\(n, m <= 10^5\))
题解
显然可以莫队,然后单次转移用树状数组优化可以做到 \(O(n\sqrt n logn)\),不过这道题只能拿20分,然后考虑如何优化莫队的单次转移。
不难发现莫队的转移可以二次离线,大概的方式等同于二次离线的板子题,所以复杂度可以优化到 \(O(n\sqrt n + nlogn)\)。
[APIO/CTSC 2007]数据备份
题意
数轴上给你 n 个点,你需要找出 K 个点不重复的点对,是的点对之间的距离之和最小。 (\(n <= 10^5\))
题解
考虑贪心,显然点对之间是独立的,不会出现相交和包含的情况,就是说每次只会选择相邻的两个点作为一个点对,所以我们可以采用贪心,但是你发现选了 \(i, j\) 就不能选择 \(j, j+1\) 和 \(i-1, i\),所以我们可以采用可撤销贪心来解决掉这个问题。
最小mex生成树
题意
让你求出一棵生成树,使其所有边权组成的集合的mex最小。 (n, m<=10^6)
题解
你发现mex不满足单调性这个性质,所以不大能二分答案,你考虑答案能否是 \(x\) 的判定条件,如果我们把所有为x的边权的边去掉,发现还可以形成一颗生成树,那么答案可以为 \(x\),当然可以会更小,但是符合题目要求。
考虑怎么求,因为没有单调性,所以你需要把所有的都 \(judge\) 一遍,所以我们可以用线段树分治来解决这个问题,就是用个扩展域并查集来解决这个问题,时间复杂度 \(O(nlog^2n)\)。
[BJWC2010]严格次小生成树
题意
求出一棵严格次小生成树。 \(n,m <= 10^5\)
题解
我们先用 \(Kruskal\) 求出一棵最小生成树,考虑到 \(Kruskal\) 的本质是贪心思想,那么如果我们遍历每条未加入树中的边,然后找到它所形成的环中的最大的边,这个就可能是一棵次小生成树了。
我们可以选择LCT来维护或者倍增来维护最大值和次大值,维护次大值的原因是你需要严格的次小生成树。
区间本质不同子串个数
题意
给一个字符串,每次询问求 \([l, r]\) 内的不同子串个数。(\(n,m <= 10^5\))
题解
这个比求本质不同回文串还简单一点,显然先离线下来扫描线,然后考虑右端点为 \(i\) 的时的变化,发现变的只有以 \(i\) 为右端点的子串,如果我们知道它们上一次出现的位置,就可以树状数组维护差分了。
考虑怎么快速得到上次出现的位置,发现一定构成了一段段的等差序列,我们可以用LCT维护,每次 access 的过程中,每段实链一定是一段等差序列,所以我们直接用LCT维护就可以了,复杂度 \(O(nlog^2n + mlogn)\)
[2021.4.6多校省选模拟31]亚特兰大
题意
每次修改一条边的边权,每次求路径上边权的gcd为1的路径条数,修改次数 <= 100。(\(n <= 10^5\))
题解
首先可以想到莫比乌斯反演,这样就只用求是某个gcd倍数的答案了,暴力的话不难想到只留下边权为gcd倍数的边,然后用并查集维护,复杂度
\(O(nQlogn)\)。
然后有一个优化就是发现可以用可撤销的并查集,这样平均下来复杂度可以做到\(O(nQlogn*240)\),可以拿70分。
我们发现只有100条边的边权会发生变化,我们可以更换加边顺序,最后加入这100条边,然后对于每个gcd,直接跑完100组询问,这样实现的好的话可以做到
\(O(240*(n+100 * 100)logn)\),然后就可以通过了。
当然许多其他做法也是可以过的。
[2021.4.5多校省选模拟30]最小表示
题意
求最小表示下的一个字符串的本质不同子串个数。 (\(n <= 5 /times 10^4\))
题解
这种题的大概思路都是更换hash的表示方法,然后用 \(O(nlog^2)\) 的后缀数组解决问题。
因为这道题的字符集很小,所以我们可以暴力求出来以每个位置为开头的字符集变换情况,然后一个子串的 Hash
拆分成每种字符集的答案之和。
后面直接套后缀数组板子就可以了,复杂度 \(O(nlog^2*sum)\),\(sum\) 表示字符集大小。
下面给出一种可以解决字符集很大的解决办法,我们定义一个位置i的hash值为它与上一个与它相同的字符的距离,这样可以用主席树维护,其余部分不变,复杂度可以做到
\(O(nlog^3)\)。
[2021.4.5多校省选模拟30]环形划分
题意
给定一个 n 个点的无向完全图,请找出若干边不重复的三元环,使得剩下的边数 <= n - 1 (n <= 1000)
题解
就是一个构造题,考虑这样一个等式 \(i + j + k \equiv 0(mod\; n)\),发现对于一对 \([i, j]\),\(k\) 是固定的,但是我们需要排除 \(k == i\) 的情况,发现不会超过 n - 1,然后本题完结。