五月杂题选做(part 2)

上回说到:2022.5 part 1

关于难度

\(\color{gray}\bigstar\) 可以秒杀的题。

\(\color{green}\bigstar\) 思考一会儿后可以秒的题。

\(\color{blue}\bigstar\) 需要较长时间思考的题。

\(\color{Gold}\bigstar\) 看题解、稍加指点就会做的题。

\(\color{red}\bigstar\) 看题解后需要较长时间消化,甚至现在都没有完全理解的题。


ARC106D *1988 \(\color{green}\bigstar\)

已知一个长度为 \(n\) 的序列 \(a_i\) 和一个数 \(k\),对于所有 \(1\le X\le k\),求

\[\sum_{i=1}^n \sum_{j=i+1}^n (a_i+a_j)^X \]

答案对 \(998244353\) 取模。
\(n\le 2\times 10^5,k\le 300\)

标签:组合。

直接二项式定理展开,推式子就好了。

\[\sum_{i=1}^n \sum_{j=1}^n (a_i+a_j)^X=\sum_{i=1}^n \sum_{j=1}^n \sum_{p=0}^X \binom{X}{p}a_i^pa_j^{X-p}\\ =X!\sum_{i=1}^n \sum_{j=1}^n \sum_{p=0}^X \frac{a_i^p}{p!}\frac{a_j^{X-p}}{(X-p)!}\\ =X!\sum_{p=0}^X (\sum_{i=1}^n \frac{a_i^p}{p!}) (\sum_{j=1}^n \frac{a_j^{X-p}}{(X-p)!})\\ \]

可以发现是一个卷积,记 \(f_i=\sum_{j=1}^n \frac{a_j^i}{i!}\),答案就可以直接卷积得到,暴力卷积即可,时间复杂度 \(O(k^2+nk)\)

code


ARC113D *1389 \(\color{green}\bigstar\)

对于一个 \(n\times m\) 的矩阵,每个元素都 \(1\le a_{i,j}\le k\),定义 \(a_i\) 表示第 \(i\) 行的最小值,\(b_i\) 表示第 \(i\) 列的最小值,已知 \(n,m,k\),求有多少个不同的 \((a,b)\),答案对 \(998244353\) 取模。
\(n,m,k\le 2\times 10^5\)

标签:计数。

最简单的一个 ARC D,但还是想了一会儿的。

考虑一个很简单的东西,就是 \(\max(a_i)\le \min(b)\) 这个东西可以很简单可以证明,然后可以发现,除非矩阵只有一行或一列,否则只要满足上面条件的 \((a,b)\) 都可以凑出。

所以答案就简单了,枚举 \(i=\max(a_i)\),那么 \(a\) 的贡献可以直接容斥,就是 \((i^n-(i-1)^n)(k-i+1)^m\),直接算即可。

code


ARC112D *2028 \(\color{green}\bigstar\)

有一个 \(n\times m\) 的滑雪场,每次可以朝一个方向滑行,如果是冰则直接通过,直到到达一块地面或者撞到边缘停下,现在有一些地方已经是地面,求至少要把多少个冰改成地面可以使一个人从 \((1,1)\) 出发可以到达所有点。

标签:模拟(?

考虑可以到达的点一定是一整行或者一整列的,然后一块地面就是可以从一行走到一列,那么可以直接并查集维护,最后的目标就是覆盖每一行或者每一列,直接找连通块个数即可。

code


ARC126D *2332 \(\color{green}\bigstar\)

有一个长度为 \(n\) 的序列,每个元素都 \(1\le a_i\le k\),每次可以交换两个数,问至少多少次操作后满足有一个连续子序列是 \(\{1,2,3...k\}\)

\(n\le 200,k\le 16\)

标签:dp。

显然直接状压 dp,如果选了一个数,那么对答案的贡献就是选的数的逆序对个数加上到目标位置的距离,目标位置显然是移动到中位数,直接做就好了。

code


ARC139D *2816 \(\color{red}\bigstar\)

有一个长度为 \(n\) 的序列,进行 \(k\) 次操作,每次操作随机选择一个 \([1,m]\) 的数加入序列,然后把序列中第 \(x\) 小的数删除,求所有方案最后序列中的数之和的和。

\(n,m,x,k\le 2000\)

标签:计数。

神题,主要是因为题解看不懂,所以想了很久。

所有数的和可以转化为对于每个 \(1\le i\le m\),计算有多少个数 \(\ge i\) 即可。

开始时先找到 \(\ge i\) 的左端点,然后考虑这个左端点的移动,先考虑开始时在 \(x\) 右边,那么如果放 \([1,i-1]\),那么位置不变,如果放 \([i,m]\),那么就左移动一格,在 \(x\) 左边同理。

那么直接枚举左端点最后移动到了哪里,直接计算方案数即可。

code


AGC021D *2287 \(\color{green}\bigstar\)

定义一个字符串 \(s\) 的价值是它和它翻转后的串的最长公共子序列,现在已知一个串,进行最多 \(k\) 次修改操作,求修改后权值最大是多少。

\(|s|,k\le 300\)

标签:dp。

价值的定义显然是最长回文子序列。

所以可以直接区间 dp ,\(f_{i,j,k}\) 表示区间 \([i,j]\) 修改 \(k\) 次的最大值,直接转移,时间复杂度 \(O(n^3)\)

code


打了 ABC252,赛时过了 FG,由于是 unr 所以前面的题没做,Ex 想半天不会,寄。

但 psz 赛时不会 FG 我是真没想到。


ABC252G *2153 \(\color{green}\bigstar\)

已知一个先序遍历,如果有多个儿子优先遍历编号小的,求有多少棵树满足这个先序遍历。

\(n\le 500\)

标签:dp。

显然直接来,可以发现一个区间要么是一棵树,要么是多棵树,分别开 dp 数组 \(f,g\),直接每次在前面加入一棵树就好了。

code


ABC252Ex *3015 \(\color{Gold}\bigstar\)

\(n\) 个珠子,每个珠子有一个颜色和价值,现在需要每种颜色的珠子各选一个,总价值就是所有珠子价值的异或和,求所有方案总价值第 \(k\) 大的价值是多少。

\(n\le 70,v\le 2^{60}\)

标签:搜索,字典树。

这个 \(70\) 有点离谱,因为不知道有啥算法是这个复杂度的。

考虑如果暴力搜索,那么复杂度就是 \(\sum x_i=n,\prod x_i\) 的最大值,根据 powerful number 的相关知识,可以发现这个东西复杂度是 \(3^{\frac{n}{3}}\)

然后直接 meet in the middle ,分成两部分,复杂度 \(O(3^{\frac{n}{6}})\),把一半放到字典树上,然后查询第 \(k\) 大。

一个做法是二分,复杂度 \(3^{\frac{n}{6}}\log^2 v\) 爆炸。

有一个更好的做法,记录每个数在字典树上匹配哪一个节点,然后考虑这一位取什么,然后整体一起移动,这样复杂度 \(O(3^{\frac{n}{6}})\log v\)

code


bzoj3509 \(\color{blue}\bigstar\)

已知一个长度为 \(n\) 的数组 \(a\),求有多少对 \((i,j,k),i<j<k\) 满足 \(a_j-a_i=a_k-a_j\)

\(n\le 10^5,a_i\le 2\times 10^4\)

标签:分块,卷积。

先把式子变一下,变成 \(2a_j=a_i+a_k\),那么考虑枚举 \(a_j\),此时相当于找左右有多少个满足条件的,显然可以直接卷积,但复杂度 \(O(n^2\log n)\),不如暴力。

考虑和暴力平衡一下复杂度,考虑分块,对于 \(i,j,k\) 都不在一块情况,直接对左右块进行卷积,然后中间统计答案即可。对于至少有一个和 \(j\) 在同一块的情况,可以直接开桶暴力算,总时间复杂度 \(O(\sqrt{n}(n+a_i\log a_i))\),FFT 常数比较大,适当把块长调大即可。


bzoj4403 \(\color{green}\bigstar\)

给定三个正整数 \(N,L,R\),统计长度在 \(1\)\(N\) 之间,元素大小都在 \(L\)\(R\) 之间的单调不降序列的数量。输出答案对\(10^6+3\) 取模的结果。

\(n,l,r\le 10^9\)

标签:组合,分治。

首先这个东西显然是一个插板法,考虑把每个数看成一个盒子,然后把数给放进去,可以得到答案是 \(\binom{R-L+N}{R-L}\),然后相当于一个组合数前缀和,可以发现模数比较小,直接分治就好了。

code


bzoj3057 \(\color{green}\bigstar\)

定义一棵树是好的,当且仅当对于每个节点,它的左右儿子子树深度的差不超过 \(1\)。问有多少棵 \(n\) 个节点的树是好的。

\(n\le 3000\)

标签:dp。

考虑深度的范围,\(f_i\) 表示深度为 \(i\) 的树的最小节点树,\(g_i\) 表示最大节点树,那么可以发现

\[f_i=f_{i-2}+f_{i-1}\\ g_i=2^i-1 \]

两个都是 \(2^n\) 级别的,所以最后的深度是 \(\log n\) 级别的。

然后直接来,设 \(f_{i,j}\) 表示 \(i\) 个点,深度为 \(j\) 的的方案数,转移的时候枚举左子树大小即可,时间复杂度 \(O(n^2\log n)\)


bzoj4881 \(\color{blue}\bigstar\)

已知一个排列,\(p_i\) 表示 \((0,i)\)\((1,p_i)\) 有一条线段,需要把线段分成两个集合,使得这两个集合中的线段两两不交,求方案数,

\(n\le 10^5\)

标签:贪心。

线性做法,已经是 darkbzoj 上的最优解和最短解,目前没有找到另一种线性做法。

其实不是很难,考虑一个暴力做法,如果两条线段有交,那么就把这两条线段连一条边,最后相当于判断二分图方案数,这样暴力复杂度是 \(O(n^2)\) 的。

考虑对于一个线段区间 \([l,r]\) 没有一条边连向外面,那么可以发现这个区间形成一个独立的二分图,设二分图个数为 \(m\),那么答案就是 \(2^m\)

现在只剩下判断无解的问题,也就是判断是否可以划分为两个集合,那么从左向右做,相当于两个上升子序列。

这个可以直接贪心,时间复杂度 \(O(n)\)

code


bzoj4883 \(\color{Gold}\bigstar\)

有一个 \(n\times m\) 的棋盘,要求每行至少放一个白棋,每列至少放一个黑棋,一个格子放棋子有一定代价,求最小代价。

\(n\times m\le 10^5\)

标签:并查集。

这种棋盘问题一个经典的结论是考虑建出 \(n+m\) 个点然后进行连边,那么可以发现答案一定是一个基环树森林,那么直接贪心并查集维护就好了。

code


bzoj4886 \(\color{blue}\bigstar\)

\(n\) 张牌,正反面都写着数字,现在可以把这些卡片任意翻转,使得正面的数字两两不同,得分为反面数字之和,求最大得分。

\(n\le 2\times 10^5\)

标签:贪心。

不错的题。

考虑直接连边,那么可以发现满足条件的联通块一定是树或者是基环树,直接贪心就好了。

code


bzoj4836 \(\color{green}\bigstar\)

定义运算 \(*\) 表示:如果 \(x<y\)\(x*y=x+y\),否则, \(x*y=x-y\)

已知两个序列 \(a,b\),有 \(Q\) 次询问,每次询问一个数 \(c\),问有多少组 \(a_i*b_j=c\)

所有数据都 \(\le 50000\)

标签:卷积。

考虑如果是 \(a_i+b_j=c\),那么显然是个卷积,但是这里有一个限制条件。

考虑分治,类似分治 fft,每次把 \(a\) 中的一个区间和 \(b\) 中一个更大的区间卷积,这样就可以了,减法也同理。

时间复杂度 \(O(n\log^2 n)\)

code


CF1220F \(\color{green}\bigstar\) *2700

已知一个长度为 \(n\) 的排列,可以进行若干次循环移位,求多少次移位后得到的序列建出的笛卡尔树深度最小。

\(n\le 2\times 10^5\)

标签:单调栈,笛卡尔树。

有线段树做法,不过 too hard。

事实上直接来,考虑 \(1\) 左边和右边是两个不干扰的部分,因此左边做一下,右边做一下,然后直接合并即可,解决的问题变成加点,查询深度,这个可以在单调栈建笛卡尔树是顺便维护。

code


CF338E \(\color{green}\bigstar\) *2600

\(A\) 有多少长度为 \(len\) 的区 间中的数和 \(B\) 中的数完美匹配。两个数匹配当且仅当其和不小于 h。 (区间必须连续)

\(n,len\le 10^5\)

标签:线段树。

考虑先把 \(b\) 排序,那么可以和 \(a\) 中一个数匹配的一定是一段后缀,那么直接后缀加,可以发现满足条件需要满足 \(a_i-i\ge 0\),这样双指针和线段树维护即可。

code


CF724E \(\color{Gold}\bigstar\) *2900

题比较长,自己看吧。

标签:模拟网络流。

首先有一个网络流的做法就是建 \(n\) 个点然后暴力连 \(n^2\) 条边,直接爆炸,也没什么优化方法。

此时就有一种牛逼的算法:用 dp 模拟网络流。

考虑先变成最小割,然后就相当于要么割上面的,要么割下面的,如果割上面的还需要吧前面连过来的边都割了。

直接 dp,时间复杂度 \(O(n^2)\)

code


CF722E \(\color{blue}\bigstar\) *2900

有一个 \(n\times m\) 的网格图,图中有 \(k\) 个特殊点。 初始时你有一个权值 \(s\),并且只能向下或向右走, 每经过一个特殊点会使得你的权值/2(向上取整)。 求从 \((1,1)\) 走到 \((n,m)\) 时拥有权值的期望(mod \(10^9+7\))。

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

考虑每次除以 \(2\),最多 \(\log s\) 次就变成 \(1\) 了,所以可以设 \(f_{i,j}\) 表示走到第 \(i\) 个关键点,经过了 \(j\) 个关键点的方案数。

然后直接来,从前面去转移,注意容斥一下就好了。

code


CF1209G2 \(\color{Gold}\bigstar\) *3200

题比较长,自己看吧

标签:线段树。

考虑一定是吧序列变成一段段区间,答案就是 \(n\) 减去每个区间众数之和, G1 不带修,直接模拟就好了。

考虑用 set 去记录每个数出现的位置,然后区间加,那么相当于 \(0\) 的位置就是断点,分开两个连续段。

每个数都直接在左端点放入出现的位置,然后去查询最大值,这样只需要比较左右的最小值就可以判断两区间合并时的情况。

具体而言,如果维护断点复杂度会爆炸,但是可以维护区间最小值,把最小值当做是断点,这样就可以轻松维护了。

code


CF472G \(\color{blue}\bigstar\) *2800

题比较长,自己看吧。

标签:多项式,卷积,分块。

显然这个匹配可以写成一个卷积形式,但是是区间求和,很不好搞。

常见套路是直接分块,块内的和就可以直接维护了,本题需要一定的卡常技巧。

code


CF1553F \(\color{green}\bigstar\) *2300

已知一个序列 \(a\),定义 \(p_k\) 表示

\[p_k=\sum_{i=1}^k\sum_{j=1}^k a_i\bmod a_j \]

对于每个 \(i\in [1,n]\),求出 \(p_i\)

\(n,a_i\le 2\times 10^5\)

标签:树状数组。

考虑递推,那么相当于要计算

\[(\sum_{i=1}^{k-1} a_k\bmod a_i)+(\sum_{i=1}^{k-1} a_i \bmod a_k) \]

右边那个开桶,然后调和级数算,相当于单点加,区间查,直接树状数组。

左边的考虑一个数对后面的贡献,也就是区间加,单点查,也可以树状数组。

code


CF1615G \(\color{blue}\bigstar\) *3300

给定一个数列 \(a\),你需要将所有 \(a_i=0\) 的位置填上一个 \(1\sim n\) 的正整数,使得数列的「值」最大。

数列的值定义为满足以下条件的 \(k*k\) 的个数:

  • 存在 \(i\in\Z[1,n-1]\),使得 \(a_{i}=a_{i+1}=k\)

输出值最大的序列,若有多解,输出任意一个。

\(0\le a\le \min(n,600),0<n\le 3\times 10^5\)

标签:一般图最大匹配。

考虑填数的这些 \(0\) 的连续段进行讨论。

如果连续段长度为奇数,那么必然是填 \(\left \lfloor \frac{x}{2} \right \rfloor\) 个相同数,然后剩下一个和左右的进行匹配。

如果连续段长度为偶数,那么就有两种情况,要么是填 \(\frac{x}{2}\) 个相同数,要么左右各匹配一个然后填 \(\frac{x}{2}-1\) 个数。

与左右匹配可以看成是一半图最大匹配,先对不同的数值建点。

  • 如果是奇数,新建一个点,向左右的数连边。
  • 如果是偶数,新建两个点,分别向左右连边,然后这两个点连边。

然后直接跑最大匹配,带花树会寄,用随机匹配。

随机匹配也就是把边随机顺序然后跑二分图,不过输出方案比较恶心。

code


CF1615F \(\color{blue}\bigstar\) *2800

对于两个长度为 \(n\)\(01\)\(s,t\) ,你可以对 \(s\) 进行两种操作:把相邻两个 \(0\) 变成 \(1\) 或把相邻两个 \(1\) 变成 \(0\) ,定义 \(s\)\(t\) 的距离为最少操作次数使得 \(s\) 变成 \(t\) ,如过没法变则距离为 \(0\)

现在你有两个不完整的字符串,可以把其中的 \(?\) 变成 \(0\)\(1\) ,求所有情况所得到的两个 \(01\) 串的距离之和。

\(n\le 2000\)

标签:dp。

不错的题。

考虑把相邻两个相同的翻转很难搞,因为甚至是否有解也判断不了,所以考虑把所有奇数位置上的东西翻转,这样变成翻转相邻两个不同的,也就是交换相邻两个元素。

那么距离就是把所有 \(1\) 的位置排序后对应元素差的绝对值了。

考虑 dp 设 \(f_{i,j}\) 表示已经做完了 \([1,i]\),前面 \(s\) 中的 \(1\) 的个数比 \(t\)\(j\) 个的方案数,那么统计 \([i,i+1]\) 这个部分对答案的贡献,也就是 \(j\times f_{i,j}\),转移可以直接转移。

code


ARC102E \(\color{green}\bigstar\) *2484

\(n\)\(k\) 面骰子,求对于每个 \(i\) ,求出有多少种骰子方案使得没有两个骰子上的数加起来等于 \(i\)

\(n,k\le 2000\)

标签:组合计数。

考虑对于一个 \(i\) ,把所有数分成三类

  • \(x>i\) 可以乱选。
  • \(i\) 是偶数,\(x=\frac{i}{2}\),最多选 \(1\) 个。
  • 其他情况,把 \(x,i-x\) 分成一组,一组中只可以选其中一个。

直接计数即可。

code


打了 ABC253,开局秒了E,然后会了F,psz 给了我 ABCD,F 写了一会儿就过了,发现 G 是 sb 题,类似直接分块然后就好了,但细节很多,psz 去写,我先看 Ex,然后发现会了,找了 10min 矩阵树板子,终于找到了(还不如重写一遍),然后直接冲了一波,WA 了一下,结果发现是没取模。。。然后直接过了。

接下来帮 psz 调 G,然后过了。

第一次 AK ABC,非常开心,总用时 78 分钟。


ABC253Ex \(\color{green}\bigstar\) *2758

\(n\) 个点,\(m\) 条边,每次随机加一条边(可以重复加),对于每个 \(1\le k\le n-1\),求出有多少概率满足加入 \(k\) 条边后图是一个森林,答案对 \(998244353\) 取模。

\(n\le 14,m\le 500\)

标签:矩阵树定理,状压 dp。

考虑枚举森林是怎么样的,然后假设里面有 \(x\) 条边,概率就是 \(\frac{x!}{m^x}\)

那么最后的森林是怎么样的呢?直接枚举一个连通块,求出这个连通块是一棵树的方案数,也就是生成树计数,直接矩阵树定理。

然后状压 dp 合并,统计答案即可,时间复杂度 \(O(n^32^n+n3^n)\)

code


打 ARC141,晚 \(50\) 分钟进场,unr,输麻了。

psz 过 A 之后去看注意开发表重要讲话,笑不活了,直接摆烂。

开局我直接冲 D。

这个 \(2M\) 的条件明显是拿来匹配的,然后直接按 \(2\) 的幂次分类即可,但是发现寄了。

那就按去掉 \(2\) 之后的部分分类,可以发现每一个部分最多选一个,最多有 \(m\) 个部分,可以判断无解。

所以就是每个部分选一个,按倍数关系建拓扑图,然后考虑一个点选 \(2\) 的幂次。

显然,如果 \(p\)\(q\) 的幂次,那么 \(p\) 乘上 \(2\) 的幂次一定小于 \(q\),满足拓扑顺序。

想要满足条件,一个点选的幂次一定是一段区间,正反跑两边拓扑排序即可。

code

观察仔细,你会发现提交时间是 《2022-05-29 22:02:23》,是的,我差 2min 场切 *2800+,悲。


ARC141E \(\color{blue}\bigstar\) *3009

\(n^2\) 个点,每个点被表示为 \((i,j)\),有 \(Q\) 次操作,每次操作把所有 \(0\le k< n\),将 \((a_i+k,b_i+k)\)\((c_i+k,d_i+k)\) 连边。

\(n,Q\le 2\times 10^5\)

标签:并查集。

首先按 \(i-j\) 把点分类,那么可以发现操作时机上就是两个组中的点对应连边。

如果这两组一开始不是一个连通块,那么直接连通块个数减少 \(n-1\)

否则,计算这两个联通块的距离,然后相当于求个 \(\gcd\) 即可。

这些都可以用并查集维护,然后就没了。

code


posted @ 2022-05-23 20:56  houzhiyuan  阅读(144)  评论(0编辑  收藏  举报