随机乱做 Part 5
- 「CF1559D2」Mocha and Diana (Hard Version)(性质 + 并查集)
- 「CF1109D」Sasha and Interesting Fact from Graph Theory(组合计数 + 扩展 Cayley 定理)
- 「CF1672H」Zigu Zagu(思维 + 前缀和)
- 「CF1741G」Kirill and Company(状压 DP + 最短路图 + 拓扑排序)
- 「CF1473E」Minimum Path(最短路)
- 「CF1736E」Swap and Take(DP)
- 「CF321E」Ciel and Gondolas(分治决策单调性)
- 「CF1739F」Keyboard Design(AC 自动机 + DP)
- 「CF1746C」Permutation Operations(差分 + 性质)
- 「CF1746F」Kazaee(随机化 + 树状数组)
「CF1559D2」Mocha and Diana (Hard Version)(性质 + 并查集)
连通块数量较少的那一个森林最后肯定会变成一个连通块。证明考虑对于另一张图两个连通块中的点,它们在这张图中肯定是连通的,进而推出所有点都是连通的。
那么我们可以先随便一个点,把能连的边都连了。令 \(L\) 为第一张图中与这个点不连通的点集,\(R\) 为第二张图与这个点不连通的点集,那么 \(L\) 与 \(R\) 肯定不交。然后就可以把 \(L\) 和 \(R\) 中的点两两配对,这样肯定合法,因为它们在两张图中与这个点的连通性相反。
代码:https://pastebin.ubuntu.com/p/d95Nx2Pb9Q/。
「CF1109D」Sasha and Interesting Fact from Graph Theory(组合计数 + 扩展 Cayley 定理)
枚举 \(a\to b\) 路径上除开这两个点的点数 \(i\),那么就有 \(i+1\) 条边,边权 \(\in[1,m]\) 且总和为 \(m\),插板法可以知道这是 \(\binom{m-1}{i}\)。选择点的方案 \(\binom{n-2}{i}\),可以任意排列所以还要乘 \(i!\),其他边边权任意 \(m^{n-1-(i+1)}\)。然后就相当于把这 \(n\) 个点分成 \(i+2\) 个连通块,且前 \(i+2\) 个点属于不同连通块,根据扩展 Cayley 定理可知方案数为 \((i+2)n^{n-(i+2)-1}\)。那么答案就是 \(\sum\limits_{i=0}^{n-3}\binom{n-2}{i}\binom{m-1}{i}i!m^{n-1-(i+1)}(i+2)n^{n-(i+2)-1}+\binom{m-1}{n-2}(n-2)!\)。后面的是因为 \(i=n-2\) 需要特判。
代码:https://pastebin.ubuntu.com/p/GCBm3mNDF9/。
「CF1672H」Zigu Zagu(思维 + 前缀和)
记 \(x\) 为当前串中相邻两项均为 0
的数量,\(y\) 为当前串中相邻两项均为 1
的数量。
那么每一次如果选择偶数长度的串删掉,\(x\) 和 \(y\) 都会减少 \(1\)。并且如果 \(x>0\) 且 \(y>0\),总可以找到这样一个串。
如果选择奇数长度的串删掉,\(x\) 或 \(y\) 会减少 \(1\)。
经过分析,答案为 \(\max(x,y)+1\)。前缀和即可。
代码:https://pastebin.ubuntu.com/p/WhJyKWYGNw/。
「CF1741G」Kirill and Company(状压 DP + 最短路图 + 拓扑排序)
题意:
Kirill 住在一张 \(n\) 个点 \(m\) 条边的连通无向图上的 \(1\) 号节点。
他有 \(f\) 个朋友,第 \(i\) 个朋友住在 \(h_i\) 位置上。其中有 \(k(k\le 6)\) 个朋友没有车,分别为第 \(p_1\sim p_k\) 个,他们只能步行或者搭别人的车回去。一个有车的人能搭载任意数量的没车的人回到他们的家,但要保证他走的是从 \(1\) 号节点到他的家的最短路。
问最少有多少个人需要步行回家。
数据范围:\(2\le n\le 10^4,n-1\le m\le \min(10^4,\frac{n(n-1)}{2}),1\le f\le 10^4,2\le h_1\le n,1\le k\le \min(6,f),1\le p_i\le f,p_i<p_{i+1}\)。
建出最短路 DAG,那么只能在这张 DAG 上转移。
设 \(t_{i,s}\) 表示走 \(1\to i\) 的最短路,搭载没车的人的集合为 \(s\) 是否可行。这个可以记录每个节点上没车的人的集合,然后枚举子集转移。
再设 \(f_{i,s}\) 表示考虑前 \(i\) 个人,已经有车回去的人的集合为 \(s\) 是否可行。转移同样是枚举集合。
代码:https://pastebin.ubuntu.com/p/bvSp5c5w7n/。
「CF1473E」Minimum Path(最短路)
注意到如果任意减去一条边的边权,那么肯定减去边权最大的最优。如果任意给一条边的边权翻倍,那么肯定选择边权最小的。
那么只要记 \(dis_{i,0/1,0/1}\) 表示走到 \(i\),是否减去了一条边的边权,是否翻倍了一条边的边权的最短路。
正常跑 Dijkstra 即可。
代码:https://pastebin.ubuntu.com/p/dQwGpqzvjj/。
「CF1736E」Swap and Take(DP)
题意:
给定一个长度为 \(n\) 的数组 \(a\),你需要在上面做 \(n\) 次操作。
一开始你的分数是 \(0\)。
在第 \(i\) 次操作中,你可以交换数组中相邻的两个元素并且将其中一个变成 \(0\) 或者保持原数组不动。无论你是否操作,分数都会加上 \(a_i\)。
问你能得到的最大分数。
数据范围:\(2\le n\le 500,1\le a_i\le 10^6\)。
首先,我们肯定不可能把 \(0\) 加入答案中。
假设第 \(i\) 次操作加上的分数是 \(a_{p_i}\),那么肯定有 \(p_i\le p_{i+1}\)。因为如果出现 \(p_i>p_{i+1}\) 就肯定是把后面的交换到了前面,当前选的就会变成 \(0\)。
那么设 \(f_{i,j,k}\) 表示到第 \(i\) 轮,\(p_i=j\),已经进行了 \(k\) 次交换操作所能得到的最大分数。
转移可以分类讨论:
- 若 \(p_i=p_{i-1}\),相当于将上一位和这一位交换,并将这一位变成 \(0\),方程为 \(f_{i,j,k}\leftarrow f_{i-1,j,k-1}+a_j\)。
- 若 \(p_i>p_{i-1}\),就相当于之前进行了一些交换操作把 \(p_i\) 移到了 \(i\),需要 \(p_i-i\) 次。枚举 \(p_{i-1}\),方程为 \(f_{i,j,k}\leftarrow\max\limits_{x<j}(f_{i-1,x,k-(j-i)})+a_j\),前缀和优化即可。
这题的巧妙就在于将交换操作和贡献计算分开处理,将操作次数单独做一个 DP 维度。
代码:https://pastebin.ubuntu.com/p/xQhxdrmXsW/。
「CF321E」Ciel and Gondolas(分治决策单调性)
交叉 \(\le\) 包含,所以贡献形式满足四边形不等式。应该很好证明。
设 \(f_{i,j}\) 表示前 \(i\) 个人分了 \(j\) 艘船的最小沮丧值。分治转移即可。
代码:https://paste.ubuntu.com/p/VMgPjMhqTt/。
「CF1739F」Keyboard Design(AC 自动机 + DP)
考虑对于每个串,建立一张 \(12\) 个点的图,两个点之间有边当且仅当它们在这个串中相邻。
如果一个串可能在最后有贡献,那么肯定图的形态是一条链。因为有环或者度数 \(\ge 3\) 的点肯定不行。
链有正反两种形式,我们把它们都插入一个 AC 自动机里面。因为它们不可能同时贡献。
AC 自动机上每个节点记录以这个点结尾的前缀和所有后缀可能贡献之和。注意在建 AC 自动机的时候需要把这个转移,不要忘了。
然后就设 \(f_{i,j}\) 表示到第 \(i\) 个节点,这 \(12\) 个字母的选择情况是 \(j\)(一个二进制数)的最大答案。转移枚举儿子即可。
输出方案直接记录每个状态的前驱。
代码:https://pastebin.ubuntu.com/p/dcgNWdh88G/。
「CF1746C」Permutation Operations(差分 + 性质)
题意:
给定一个长度为 \(n\) 的排列 \(a\),你需要进行 \(n\) 次操作,第 \(i\) 次操作需要选择一段后缀 \(+i\)。问如何操作才能使最终序列的逆序对数量最少。
数据范围:\(1\le n\le 10^5\)。
场上看错题还能过 Pretests,佛了。掉大分。FST!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
大胆猜想一波最后肯定可以将序列变成不降(即逆序对数量为 \(0\))。
其实是可以做到的:把序列变成差分序列,即 \(d_i=a_{i+1}-a_i\),那么最终序列不降等价于 \(\forall 1\le i<n,d_i\ge 0\)。那么因为 \(a_{i+1}>0\),所以 \(d_i>-a_i\),只需要把 \(d_i\) 加上 \(a_i\) 就行,即在第 \(a_i\) 次操作选择 \([i+1,n]\) 这段后缀。
代码:https://pastebin.ubuntu.com/p/475KF735QB/。
「CF1746F」Kazaee(随机化 + 树状数组)
题意:
给定一个长度为 \(n\) 的序列,有 \(q\) 次操作如下:
1 i x
,将 \(a_i\) 变成 \(x\);2 l r k
,查询 \([l,r]\) 中是不是每个数都出现了 \(k\) 的倍数次。数据范围:\(1\le n,q\le 3\times10^5,1\le a_i,x\le 10^9,1\le k\le n\)。
关于出现次数,一定要想到随机权值!!!!!!!!!!!!!!!!!!!!!!!!!!!!1
这题中,我们可以先离散化,把值域变小,然后给每个数赋上一个随机的权值。修改直接树状数组;出现次数为 \(k\) 的倍数的条件就可以使用区间和是否为 \(k\) 的倍数来判断,也可以用树状数组。因为一次正确率可能没有那么高,所以可以多做几次,每次都满足条件才说明这个区间满足条件,\(30\) 次差不多了。