Atcoder-Countings3
- Atcoder-Countings3
- Intro
- AC01 [ABC266G] Yet Another RGB Sequence(2045)
- AC02 [ARC162E] Strange Constraints(2780)
- AC03 [ARC162F] Montage(3190)
- AC04 [ARC162D] Smallest Vertices(2568)
- AC05 [ARC132C] Almost Sorted(1616)
- AC06 [ABC309G] Ban Permutation(2372)
- AC07 [ABC297F] Minimum Bounding Box 2(1990)
- AC08 [ABC003D] AtCoder社の冬(2033)
- AC09 [ABC242F] Black and White Rooks(2268)
- AC10 [ARC140D] One to One(2443)
- AC11 [ARC146C] Even XOR(2428)
- AC12 [AGC030D] Inversion Sum(2712)
- AC13 [ABC299F] Square Subsequence(2366)
- AC14 [ARC104D] Multiset Mean(2251)
- AC15 [ABC281G] Farthest City(2304)
- AC16 [ABC234G] Divide a Sequence(2306)
- AC17 [ABC292G] Count Strictly Increasing Sequences(2340)
- AC18 [ABC276G] Count Sequences(2278)
- AC19 [ABC279G] At Most 2 Colors(2431)
- AC20 [ABC282G] Similar Permutation(2412)
- AC21 [AGC043D] Merge Triplets(2708)
- AC22 [ARC065F] シャッフル(2652)
- AC23 [ABC301F] Anti-DDoS(2548)
- AC24 [ABC200F] Minflip Summation(2556)
- AC25 [AGC050C] Block Game(2528)
Atcoder-Countings3
Intro
.
AC01 [ABC266G] Yet Another RGB Sequence(2045)
Atcoder:[ABC266G] Yet Another RGB Sequence
洛谷:[ABC266G] Yet Another RGB Sequence
Problem
求符合要求的字符串个数,对 \(998244353\) 取余。
满足要求的字符串 \(s\) 具备以下特性:
- \(s\) 由
r
、g
、b
构成。 - \(s\) 中有 \(R\) 个
r
,\(G\) 个g
,\(B\) 个b
,\(k\) 个rg
。
$ 1 \leq R,G,B \leq 10^6, 0 \leq K \leq \operatorname{min}(R,G) $。
Solution
高中排列组合题。把 \(k\) 个 rg
打包成 x
,剩下 \(R - k\) 个 r
,\(G - k\) 个 g
。把 x, r, g, b
排列,且不能出现新的 rg
。
考虑拎 x, r, b
出来排,然后 g
再插空。
\(x\) 个无标号小毬插进 \(y\) 个有标号盒子的方案数为 \(\binom{x + y - 1}{x}\)。
AC02 [ARC162E] Strange Constraints(2780)
Atcoder:[ARC162E] Strange Constraints
洛谷:[ARC162E] Strange Constraints
Problem
给定长度为 \(n\) 的序列 \(A\),求序列 \(B\) 的个数模 \(998244353\),满足以下条件:
- 值域 \([1, n]\)。
- \(i\) 的个数不超过 \(A_i\)。
- \(B_i\) 的个数不超过 \(A_i\)。
\(1 \le n \le 500\)。
Solution
神仙。但大家普遍认为这题很简单。
记 \(c_i\) 表示 \(i\) 在 \(B\) 中出现的次数,\(s_i = \sum\limits_{j = 1}^{n}[A_j \ge i]\)。
\(A_i\) 一方面限制了 数(在 \(B\) 中的个数),一方面限制了(填入 \(B\) 中的数)位置。
由此,先思考怎样的数可以填入 \(B\) 中:\(c_i \le A_i\) 的所有的 \(i\)。
再思考这些数具体可以填哪些位置:\(c_j \le A_i\) 的 \(j\) 可以填在 \(B\) 的位置 \(i\) 上。
安排一个填数的顺序:发现填数的两个步骤 —— 选数、定位 —— 均与出现次数有关,因此可以按照数的出现次数从大到小填入。
设计状态 \(f_{i, j, k}\) 表示考虑 \(B\) 中填入出现次数 \(\ge i\) 的数,\(B\) 中共有 \(j\) 种数(\(j \le s_i\)),共填入了 \(k\) 个数(\(k \le s_i\))。
转移时,枚举填入 \(B\) 中出现次数 $ = i$ 的个数 \(x\)(算是常见套路了)(\(x + j \le s_i\)),从 \(f_{i + 1, j, k}\) 转移到 \(f_{i, j + x, k + ix}\)。
先选数:之前已选 \(j\) 种数,现共有 \(s_i\) 种数可填入,故可选择 \(s_i - j\) 种数,从中选 \(x\) 种数,方案为 \(\binom{s_i - j}{x}\)。
再填数:之前填的 \(k\) 个数的位置不用再考虑,只需考虑新填的 \(ix\) 个数。现共有 \(s_i\) 个可以填入的位置,故可选择 \(s_i - k\) 个位置,将 \(ix\) 个数填入后取消相同元素(以及空位)间的顺序,方案为 \(\frac{(s_i - k)!}{(i!)^{x}(s_i - k - ix)!}\)。
综上,转移为:
边界为 \(f_{n + 1, 0, 0} = 1\),答案为 \(f_{0, n, n}\)。
关于时间复杂度,\(x\) 和 \(j\) 的上界都是 \(\frac{n}{i}\) 级别的,累加算一下时间复杂度是 \(O(n^3)\) 级别的。
AC03 [ARC162F] Montage(3190)
Problem
给定正整数 \(N, M\) 和 \(N\) 行 \(M\) 列的 \(01\) 矩阵 \(A\),共有 \(2^{NM}\) 种可能的矩阵。求有多少种矩阵满足以下条件:
对于所有满足 \(1 \leq a < c \leq N\) 和 \(1 \leq b < d \leq M\) 的整数组 \((a, b, c, d)\),都有 \(A_{a, b} \times A_{c, d} \leq A_{a, d} \times A_{c, b}\)。
答案对 \(998244353\) 取模。
Solution
\(A_{a, b} \times A_{c, d} \leq A_{a, d} \times A_{c, b}\) 等价于:若 \(A_{a, b} = A_{c, d} = 1\),则 \(A_{a, d} = A_{c, b} = 1\)。注意 \(a < c\) 且 \(b < d\)。
把空白行列删掉,然后找性质,发现 \(l_i \le l_{i - 1} \le r_i + 1\),\(r_i \le r_{i - 1}\),且每一行必为连续的 \(1\)。
这些都是把空白行列删掉之后得出的强大性质!这个神仙思路把整个题的分给提上去了。
然后就是简单问题了。
记 \(f_{i, l, r}\) 表示到第 \(i\) 行连续段为 \([l, r]\) 的方案数。
二位前缀和维护。边界为 \(f_{1, i, m} = 1\)。
一个 \(f_{i, l, r}\) 对答案的贡献为 \(\binom{n}{i}\binom{m}{l - 1}f_{i, l, r}\),相当于选择哪些行/列作为非空白行/列。
实现时 \(f\) 的行编号那一位可以省掉,因为上一行的 \(f\) 存进了二位前缀和里,之后用不到了。
AC04 [ARC162D] Smallest Vertices(2568)
Atcoder:[ARC162D] Smallest Vertices
洛谷:[ARC162D] Smallest Vertices
Problem
在本问题中,当我们提到有根有向树时,我们指的是所有边都指向从根到叶子的有根树。
给定一个使得其总和为 \(N-1\) 的非负整数序列 \(d=(d_1,d_2,\ldots,d_N)\)。
对于带编号从 \(1\) 到 \(N\) 的顶点,假设 \(1\) 是根,我们将其点度数定义为 \(d_i\)。
我们称满足以下条件的根付有向树为好树:
- 点 \(i\) 的出度是 \(d_i\)。
此外,对于好树的顶点 \(v\),定义 \(f(v)\) 为“包含顶点 \(v\) 的子树中的顶点(包括 \(v\))的顶点编号的最小值”。我们将满足 \(f(v)=v\) 的顶点称为好顶点。
求好树中所有好顶点的总数,将其对 \(998244353\) 取模后的余数。
- $ 2\ \leq\ N\ \leq\ 500 $
- $ 0\ \leq\ d_i\ \leq\ N-1 $
- $ d_1\ \geq\ 1 $
- $ \sum_{i=1}^N\ d_i\ =\ N-1 $
Solution
注意题目给的是出度不是度数。
则若只是问好树的数量,由 Prufer 序列可得知答案为 \(\frac{(n - 2)!d_1}{\prod\limits_{i = 1}^{n}d_i!}\)。这里乘 \(d_1\) 是因为 \(1\) 的度数就为出度。之后的这种形式同理。
现在询问这些好树中好顶点的数量,观察数据规模较小,不妨考虑枚举顶点,看有多少好树满足该点为好顶点。
设当前枚举的点为 \(u\),则 \(u\) 的子树节点编号均在 \([u, n]\) 间。
先填 \(u\) 子树:选择点集 \(S(u \in S)\),\(u\) 子树的方案数为:
再将 \(u\) 子树作为整体与其它点形成完整的好树:
这两个乘起来分母是定值,于是只需要确定 \(|S|\) 而非枚举 \(S\),同时做一个 dp 求出 \(|S|\) 对应的 \(S\) 的数量。
计 \(f_{i, j, k}\) 表示考虑选取编号 \(\ge i\) 的点,共选 \(j\) 个点,这些点的 \(d\) 值之和为 \(k\) 的方案数。讨论是否选 \(i\):
考虑 \(S\) 中必选 \(u\),\(|S| = j + 1\) 的 \(S\) 共有 \(f_{u + 1, j, j - d_{u}}\) 个。将其乘上之前那两坨式子贡献进答案:
注意 \(u = 1\) 时,\(|S|\) 只能为 \(n\)。其实 \(u = 1\) 时的贡献就是好树的个数。
注意 \(d_u = 0\) 时,\(|S|\) 只能为 \(1\)。该情况的贡献也是好树的个数。
实现时可以把 \(f\) 的第一维滚掉,但是我懒。
AC05 [ARC132C] Almost Sorted(1616)
Atcoder:[ARC132C] Almost Sorted
Problem
定一个长度为 \(n\) 的数字序列 \(A\),由 \(1\) 到 \(n\) 之间的整数和 \(-1\) 组成。还有一个整数 \(d\)。
现在要对这个序列进行变换,将 \(A\) 中所有为 \(-1\) 的 \(a_i\) 替换成一个数字,使得得到的序列 \(P\),满足:
- \(\forall a_i \ne -1,p_i = a_i\)。
- \(P\) 是 \(1\) 到 \(n\) 的一个排列。
- \(\forall |p_i-i| \leq d\)
试问有多少种这样的排列 \(P\)。答案对 \(998244353\) 取膜。
\(1 \le d \le 5, d < n \le 500\)。
Solution
状压。状压什么?直接状压 \(n\) 个数的选取情况显然是不可取的。
考虑当前位置 \(i\) 可以填的数只在 \([i - d, i + d]\) 之间,我们状压这 \(2d + 1\) 个数的选取情况。
转移的时候保证 \(a_i\) 不会与 \([i - d, i + d]\) 之间已经填过的数产生矛盾,这里可以用 \(a_{i - 1}\) 的状态右移进行判断。
只要 \(a_i\) 在 \([i - 2d - 1, i + 2d + 2]\) 的范围内不与其他位置发生冲突,整个序列就是合法的,因为与 \(a_i\) 产生冲突的位置也只能是这个小范围,因此这样状压的做法是正确的。
AC06 [ABC309G] Ban Permutation(2372)
Atcoder:[ABC309G] Ban Permutation
Problem
求 \(\forall i \in [1, n], |i - p_i| \ge d\) 的 \(n\) 阶排列数。\(d \le 5, 1 \le n \le 100\)。
Solution
上面那道题套一个容斥即可。
状压时再多记一维记录有多少个位置上 \(|i - p_i| < d\),以便之后确定容斥系数。
AC07 [ABC297F] Minimum Bounding Box 2(1990)
Atcoder:[ABC297F] Minimum Bounding Box 2
洛谷:[ABC297F] Minimum Bounding Box 2
Problem
在一个 \(H\) 行 \(W\) 列的网格图上随机选择 \(K\) 个点。定义当前局面的分数为最小的可以围住这 \(K\) 个点的矩形的面积。
请求出所有局面中分数的期望值,输出时对 \(998244353\) 取模。
- $ 1\leq\ H,W\ \leq\ 1000 $
- $ 1\leq\ K\ \leq\ HW $
Solution
不难,但一直推错。
枚举矩形边长 \(x, y\),对答案贡献 \((n - x + 1)(m - y + 1)w(x, y)\),\(w(x, y)\) 表示将 \(k\) 个点放入边长为 \(x, y\) 的矩形且四条边上均有点的方案数。
\(w(x, y)\) 可以容斥计算。
最后答案除以 \(\binom{nm}{k}\)。
容斥:(有点恶心)
注意当 \(x = 1\) 且 \(y = 1\) 时,要特判 \(w(1, 1) = \binom{1}{k}\)。
AC08 [ABC003D] AtCoder社の冬(2033)
Problem
把 \(a\) 个 \(A\) 和 \(b\) 个 \(B\) 放进 \(n \times m\) 的矩阵(一个格子最多放一个东西),然后作 最小 的矩形把所有 \(A, B\) 框起来,求出这个矩形恰好是 \(x \times y\)(限制方向)的方案数。
第一行输入 \(n, m\),第二行输入 \(x, y\),第三行输入 \(a, b\)。
答案对 \(1000000007\) 取模。\(1 \le n, m \le 30\)。
Solution
试一试!
AC09 [ABC242F] Black and White Rooks(2268)
Atcoder:[ABC242F] Black and White Rooks
洛谷:[ABC242F] Black and White Rooks
Problem
考虑在一个 \(N\) 行 \(M\) 列的棋盘上放置 \(B\) 只黑车和 \(W\) 只白车。一个好的放置方式应满足以下条件:
- 所有车放在方格内,且一个方格至多放一只车。
- 没有一对黑车和白车可以互相攻击,即没有一对黑车和白车,它们中的一个可以一步到达另一个所在的方格。
这里,车一步可以到达与之同行或同列的任一方格,前提是不跨过其它棋子。
求好的放置方式的数目。由于答案可能很大,输出对 \(998244353\) 取模的结果。同种颜色的车不区分。
- \(1 \le N,M \le 50\);
- \(1 \le B,W \le 2500\);
- \(B+W \le N \times M\);
- 所有输入的数是整数。
Solution
记 \(f(x, y, c)\) 表示用 \(c\) 个棋子使得恰好 \(x\) 行和 \(y\) 列上至少有一个棋子,则答案为:
其中 \(f(x, y, c)\) 可以用容斥计算,即考虑枚举有多少行 / 列没有棋子:
AC10 [ARC140D] One to One(2443)
Problem
你有一个长度为 \(n\) 的序列 \(a_1,a_2,\dots,a_n\),其中每个元素都是 \([1,n]\) 中的整数。
初始时有编号为 \(1 \sim n\) 的 \(n\) 个节点,对于每个 \(1\leq i \leq n\),从 \(i\) 向 \(a_i\) 连一条无向边。\(a_i=-1\) 表示 \(a_i\) 还没有确定。你需要对所有可能的 \(a\) 序列求出图中连通块数量的和对 \(998244353\) 取模的结果。
\(1 \le n \le 2000\)。
Solution
-
最终每个连通块一定是一个基环树。
-
起始时每个连通块是一棵树或基环树,其中基环树中没有 \(a_i = -1\) 的点,树中只有一个 \(a_i = -1\) 的点。
由于最终形成的均为基环树,考虑 对环计数。
初始的基环树可以直接拎出来,每个基环树对答案的贡献为 \(n^{m}\),其中 \(m\) 是树的数量。
连向基环树的树对答案没有贡献。考虑树与树之间连接的贡献:
把一棵树看作一个点,设 \(f_{i, j}\) 表示用 \(i\) 棵树拼成长度为 \(j\) 的环的方案数(环不定序,点有标号),且 拆贡献计算,枚举长度为 \(j\) 的环,每次只统计这个环对答案的贡献。
不把当前树接到环上:\(f_{i, j} \leftarrow f_{i - 1, j}\);接到环上:\(f_{i, j + 1} \leftarrow sz_i \times f_{i - 1, j}\)。
对于长度为 \(j\) 的环,贡献为:\(f_{m, j} \times (j - 1)! \times n^{m - j}\),\((j - 1)!\) 是环的定序,\(n^{m - j}\) 是对剩下 \(m - j\) 个 \(-1\) 的任意分配。
AC11 [ARC146C] Even XOR(2428)
Problem
请输出满足下述条件的集合 \(S \subseteq \{0,1,2,\ldots,2^N-1\}\) 的个数对 \(998244353\) 取模后的结果。
-
对于所有 \(S\) 的非空子集 \(T\),均满足下列条件之一:
-
\(\lvert T \rvert\) 为奇数;
-
\(T\)中所有元素的异或和不为 \(0\)。
-
\(1 \le N \le 2 \times 10^5\),保证输入数据全为整数。
Solution
容易想到线性基中的一个结论:大小为 \(n\) 的线性基(无 \(0\))可以表示的数的个数为 \(2^{n} - 1\) 个,并且不同子集的异或和不同。
则当 \(|S| > n\) 时,\(S\) 中必能异或出 \(0\),因此 \(|S| \le n\)。
对于没有奇数限制的问题,将元素的选取分步考虑,易知答案为:
其中 \(\frac{1}{i!}\) 是去序。
然后考虑有奇数限制怎么做。根据原题面的定义(所有偶子集的异或和均不为 \(0\)),不难发现,加入一个元素 \(x\) 不合法,当且仅当存在一个奇子集的异或和 \(= x\)。
然后 大胆猜测上界 = 答案,即不合法的元素数量等于 \(2^{c - 1}\),\(c\) 表示加入新元素前集合的大小。
在考虑奇数限制之前,需要先摆出一个结论:若只要求偶子集异或和不为 \(0\),则所有的奇子集异或和不同。
简要说明:假设现在有奇子集 \(S, T(S \neq T)\),记 \(U = S\cup T - S\cap T\),则 \(U\) 为偶子集且 \(U\) 的异或和等于 \(S, T\) 异或和的异或和(\(S, T\) 相交的部分被异或了两次),即 \(U\) 的异或和为 \(0\),与限制矛盾。
用反证法逆向再考虑一遍,能发现这两个条件互为充要条件。(大概要构造出一组奇偶性相同的 \(S, T\),然后再根据 \(S, T\) 相交集合的奇偶性分类讨论一下)
现在重新整理答案。第一个加进去的数可以从 \(0 \sim 2^{n - 1}\) 任选(现在可以把 \(0\) 放进集合中了!)。接下来加进去的数的方案,要从 \(2^n\) 个数中减去奇子集数量。
注意,由于改变了不合法元素的条件,\(|S|\) 的上界变为了 \(n + 1\),而不是 \(n\)。
所以答案为:
\(S = \emptyset\) 也是一种方案哦!
AC12 [AGC030D] Inversion Sum(2712)
Atcoder:[AGC030D] Inversion Sum
Problem
给你一个长度为 \(n\) 的数列,然后给你 \(q\) 个交换操作,你可以选择操作或者不操作,问所有情况下逆序对的总和对 \(10^9 + 7\) 取模。
\(n\leq 3000\),\(q\leq 3000\)。
Solution
经典套路,容易想到利用期望计数。
而最终序列的期望逆序对数为 \(\sum\limits_{i = 1}^{n - 1}\sum\limits_{j = i + 1}^{n}P(a_i > a_j)\)。
记 \(f_{i, j}\) 表示 \(a_i > a_j\) 的概率,发现每次交换只会修改 \(O(n)\) 个 \(f\) 的值(即与 \(x, y\) 相关的所有 \(f\) 值),简单维护即可。
最终答案为 \(2^{q}\sum\limits_{i = 1}^{n - 1}\sum\limits_{j = i + 1}^{n}f_{i, j}\)。
时间复杂度 \(O(n(n + q))\)。
AC13 [ABC299F] Square Subsequence(2366)
Atcoder:[ABC299F] Square Subsequence
洛谷:[ABC299F] Square Subsequence
Problem
给定一个由小写英文字母组成的字符串 \(S\)。计算满足以下条件的非空字符串 \(T\) 的数量,答案对 \(998244353\) 取模。
将 \(T\) 复制一倍形成 \(TT\),则 \(TT\) 是 \(S\) 的子序列(不一定连续)。
\(|S| \le 100\)。
Solution
AC14 [ARC104D] Multiset Mean(2251)
Atcoder:[ARC104D] Multiset Mean
Problem
给定 \(n,k, m\)。对于 \(\forall x, 1 \le x \le n\),求每个元素大小在 \([1, n]\) 中,平均数为 \(x\) 且相同元素不超过 \(k\) 个的可重整数集的数量,对 \(m\) 取模。
\(1 \le n, k \le 100\),\(m\) 为质数。
Solution
把每种数值看作一种物品,每种物品的数量为 \(k\) 个,价值为数值本身,重量为 \(1\),求价值为重量的 \(x\) 倍的方案数。
这个价值为重量的 \(x\) 倍就很讨厌,不方便统计答案,但如果 \(x = 0\) 时,就只需所有数的和加起来为 \(0\),最终价值是确定的。
那么我们每选取一个数,就将这个数减 \(x\),也就是选的数值落在 \([1 -x , n - x]\) 中。
把数值本身塞进下标做多重背包,考虑到要对所有 \(n\) 个 \(x\) 求出方案数,不妨把 \([1 - x, n - x]\) 拆成 \([1 - x, 0), \{0 \}, (0, n - x]\),\(0\) 可以选 \([0, k]\) 个,剩下的正负两区间和为 \(0\)。两个部分其实本质是一样的,我们只需要求出用 \(1 \sim i\) 获得价值为 \(j\) 的方案数 \(f_{i, j}\),则对于 \(x\),答案为:
注意减一以避免空集。
对于多重背包的部分,直接做是 \(O(n^3k^2)\) 的(价值值域为 \(O(n^3k)\))。
但是可以优化到 \(O(n^3k)\)。
AC15 [ABC281G] Farthest City(2304)
Atcoder:[ABC281G] Farthest City
Problem
构造一张 \(N\) 个点的无向连通图,边权都是 \(1\)。记图中 \(1\) 到 \(u\) 的最短路径长度为 \(d_u\),你需要保证 \(\max\{d_1,d_2,...,d_{N-1}\}\) 严格小于 \(d_N\),求构造方案数模 \(M\) 的值。无重边无自环,两个方案不同当且仅当存在一条边仅在一个方案中出现。
Solution
按照 \(d\) 从小到大 分层 加点。第零层是 \(\{1 \}\),最后一层是 \(\{n \}\)。
设 \(f_{i, j}\) 表示共确定了 \(i\) 个点,最外层点数为 \(j\) 的方案数。
枚举当前在最外层加了 \(x\) 点,运用组合数学进行转移:
最后点 \(n\) 单独考虑进去,答案为 \(\sum\limits_{j}f_{n - 1, j} \times (2^j - 1)\)。
AC16 [ABC234G] Divide a Sequence(2306)
Atcoder:[ABC234G] Divide a Sequence
洛谷:[ABC234G] Divide a Sequence
Problem
给定长度为 \(N\) 的序列 \(A\),我们定义一种将 \(A\) 划分为若干段的方案的价值为每一段的最大值减去最小值的差的乘积,你需要求出所有划分方案的价值的总和,答案对 \(998244353\) 取模。
\(1 \le N \le 3 \times 10^5, 1\le A_i \le 10^9\).
Solution
暴力 dp:设 \(f_i\) 表示考虑前 \(i\) 个数的划分的贡献和,枚举转移点 \(j\):
\(f_{i} \leftarrow \forall{1 \le j < i}, f_{j - 1}(\max(a_j \dots a_i) - \min(a_j \dots a_i))\)。初始化 \(f_0 = 1\)。
考虑拆贡献,对 \(f_{j - 1}\max(a_j \dots a_i)\) 和 \(-f_{j - 1}\min(a_j \dots a_i)\) 分别计算。
由于两者本质类似,这里只分析前者。方便叙述,记 \(w(j, i) = \max(a_j \dots a_i)\)。
统计到 \(i\) 时 \(g_{j} = f_{j - 1}w(j, i)\) 的前缀和 \(s_i\)。当 \(i\) 向 \(i + 1\) 转移时,由于 \(w(j, i)\) 变成了 \(w(j, i + 1)\),若 \(x\) 为 \(i + 1\) 之前最远的位置使得 \(w(x, i) < a_{i + 1}\),则 \(x \sim i\) 的 \(g\) 值就要被重新计算,而前面的值可以沿用。加上 \(g_{i + 1} = f_{i}a_{i + 1}\),转移可以描述为:
\(s_{i + 1} = s_{x - 1} + a_{i + 1}\sum\limits_{k = x - 1}^{i - 1}f_{k} + f_{i}a_{i + 1}\)。
对后者也算出来一个类似的前缀和合起来就能得到 \(f_{i + 1}\)。过程用单调栈维护。
需要注意的是,我们只是保证了转移时的 \(s\) 的正确性,并没有对所有的 \(s\) 值进行更新。私以为此题的 diff 值给在了这一个 trick。(其实 diff 值是根据赛时的通过情况确定哒 )
AC17 [ABC292G] Count Strictly Increasing Sequences(2340)
Atcoder:[ABC292G] Count Strictly Increasing Sequences
洛谷:[ABC292G] Count Strictly Increasing Sequences
Problem
你有 \(n\) 个数,每个数长度为 \(m\)。
不过这 \(n\) 个数中,可能有某些位不确定,需要你在每个 ?
位置上 \(0\) 到 \(9\) 之间填一个数。设你填出来的序列是 \(\{S_i\}\)。
请你求出,在所有可能的填数方案中,有多少种满足 \(S_1 < S_2 < \dots < S_n\)?对 \(998244353\) 取模。允许前导零存在。
数据范围:\(n,m \le 40\)。
Solution
被爆踩了。
先考虑最高位:一定形似一段连续的 \(0\),然后是一段连续的 \(1\),等等。
对于连续的一段区间里,次高位又可以以同样的方式划分,如此向低位确定数,启发我们可以用区间 dp。
由于高位的连续段是由低位的连续段拼起来的,所以应该从低位往高位 dp。
设 \(f[i][l][r][x]\) 表示考虑到从低到高的第 \(i\) 位,在 \([l, r]\) 区间内第 \(i\) 位上的元素均 \(\ge x\) 且以第 \(i\) 位为最高位的数满足严格升序的方案数。
初始化 \(f[0][i][i][0] = 1\),答案为 \(f[m][1][n][0]\)。
转移时枚举第一个连续段的位置 \(k\) 以及填的数值 \(c\),有以下转移:
时间复杂度为 \(O(c^2mn^3)\)。\(c\) 为字符集大小。
看题解还有更优的做法,待补。
AC18 [ABC276G] Count Sequences(2278)
Problem
计算有多少个 \(N\) 个元素的数组 \(A = (a_1,...,a_N)\) 满足以下条件,并且将结果对 \(998244353\) 取模。
- \(0 \le a_1 \le a_2 \le...\le a_N \le M\)
- 对于每一个 \(i = 1,2,..,N-1\),满足 \(a_i\) 和 \(a_{i+1}\) 对 \(3\) 取模的余数不同。
\(2 \le N \le 10^7,1 \le M \le 10^7.\)
Solution 1
写在前面:感觉此题无论是组合解法还是生成函数解法都非常有趣!
将数组 \(A\) 进行 差分,记 \(b_{i} = a_{i} - a_{i - 1}\)(特别地,\(b_1 = a_1\)),则需满足 \(\forall i(2 \le i \le N), b_i \not\equiv 0 \pmod{3}\),且 \(\sum\limits_{i = 1}^{N}b_i = a_N \le M\)。
由于 取模 的特殊结构,写成 \(b_i = 3x + y\)。不妨先忽略掉 \(3x\),因为在所有的 \(y\) 确定之后,可以视作将确定数量的 \(3\) 插入 到 \(b_i\) 中去。
记 \(c_i = b_i \bmod{3}\),则需满足 \(\forall i(2 \le i \le N), c_i = 1 \text{ or } 2\)。这又是一个经典结构([AGC023C] Painting Machines),先把所有的 \(b_i(2 \le i \le N)\) 填上 \(1\),再枚举放 \(w\) 个 \(2\),从 \(N - 1\) 个位置中选出 \(w\) 个加一。然后再枚举 \(c_1\) 填 \(0 / 1 / 2\),最后将 \(3\) 进行一个小毬放盒问题。
由于 \(3\) 的数量也需要枚举,但时间复杂度已经不支持了,所以应该预处理出 \(f_{x}\) 表示将 \(x\) 个 \(3\) 插入到 \(N\) 个 \(b_i\) 的方案数,再对 \(f\) 求出前缀和 \(s\)。
答案形式化为:
注意判断下标不能非负。
Solution 2
最朴素的想法应该是 dp,然后用数据结构维护。
记 \(f_{i, j}\) 表示考虑前 \(i\) 个位置且 \(a_i = j\) 的方案数。
但 \(10^7\) 用数据结构是很难冲过去的。考虑用 生成函数优化 dp。
记 \(F_i(x) = \sum\limits_{j = 0}f_{i, j}x^{j}\)。
当 \(i = 1\) 时:\(F_i(x) = \sum\limits_{j \ge 0}x^j = \frac{1}{1 - x}\)。
当 \(i > 1\) 时:\(F_i(x) = \sum\limits_{j \ge 0}\left( \sum\limits_{k \le j, k\not\equiv j\pmod{3}}f_{i - 1, k} \right)x^{j}\)。然后怎么化呢?
我们没必要根据展开式的标准形式来确定其封闭形式,也许可以做得更大胆一些。
考察 \(f_{i - 1, k}\) 对所有它能贡献到的 \(f_{i, j}\):
现在可以观察答案了。\(ans = \sum\limits_{i = 0}^{m}f_{n, i} = \sum\limits_{i = 0}^{m}[x^i]F_n(x)\)。发现 \(F_n(x)\) 可以直接被递推出来:
快乐推答案:
这里貌似又是一个套路?将多项式乘上 \(\frac{1}{1 - x}\) 后,新多项式的系数表示原多项式系数前缀和。这是显而易见的。
\(\frac{1}{(1 - x)^2}\) 表示对多项式的系数求 \(2\) 阶前缀和,因此可以先忽略掉,否则拆开之后过于繁琐。
把 \(\frac{1}{(1 - x)^2}\) 随便扔给一个多项式求二阶前缀和后,再与另一个多项式卷起来,可以线性得到 \(\frac{F_n(x)}{1 - x}\) 的第 \(m\) 项结果。
此题对我的生成函数应用有着很大影响,同时应该感谢 这篇题解 的细致讲解。
AC19 [ABC279G] At Most 2 Colors(2431)
Atcoder:[ABC279G] At Most 2 Colors
Problem
现在有一个 $ 1\times N $ 的格子和 $ C $ 种颜色。
每一个格子上都涂了这 $ C $ 种颜色的其中一种,并且任意相邻的 $ K $ 个格子最多有两种不同的颜色。
准确地说,对于每一个 $ i(1\le i\le N-K+1) $ ,格子 $ i,i+1,\cdots,i+K-1 $ 中,最多存在两种不同颜色。
求出有多少种方案给这些格子染色,对 $ 998244353 $ 取模。
\(2 \le K \le N \le 10^6 , 1 \le C \le 10^9\).
Solution
考虑右端加进一个元素。分为这两种情况:
前 \(K - 1\) 个格子的颜色一样,则此时可以将当前格子涂成任意一种颜色。
前 \(K - 1\) 个格子的颜色不一样,则此时有两种可以涂的颜色。
设 \(f_{i, j}\) 表示考虑前 \(i\) 个格子,第 \(i\) 个格子之前颜色相同的格子数为 \(j\) 个的方案数。
则有以下转移:
- \(f_{i + 1, j + 1} \leftarrow f_{i, j}(j < K - 1), f_{i + 1, K - 1} \leftarrow f_{i, K - 1}\):与上一个格子填相同颜色
- \(f_{i + 1, 1} \leftarrow f_{i, j}(j < K - 1)\):前 \(K - 1\) 个格子颜色不同,且与上一个格子填不同颜色
- \(f_{i + 1, 1} \leftarrow (C - 1) \times f_{i, K - 1}\):前 \(K - 1\) 个格子颜色相同,且引入新的颜色
初始化 \(f_{1, K - 1} = C\)。ABC279G \(O(nk)\)
对于 \(f_{i, j}\) 的第二维,我们只需要存到 \(K - 1\) 即可;第一维可以滚动数组优化,于是空间上可以接受。
然后想到了一个很 naive 的做法,对于后两个递推式,很显然可以线段树进行优化;对于第一个递推式,可以让 \(f_{i + 1, j}\) 直接去继承 \(f_{i, j}\),而让其它递推式的第二维做出改变。本质上是达到了一种 循环移位 的效果。ABC279G \(O(n\log{k})\)
这种做法时间复杂度劣并且移位时细节很烦,应该有更优的做法。
upd:铸币吧怎么怎么菜啊,这怕不是个 ABC 的 E 题。
直接设 \(dp_i\) 表示考虑前 \(i\) 个位置的方案数。
若 \(i\) 与 \(i - 1\) 颜色相同:\(dp_i \leftarrow dp_{i - 1}\)。
否则分两类讨论:
- \(i - K + 1 \sim i - 1\) 颜色相同:\(dp_i \leftarrow (C - 1) \times dp_{i - K + 1}\)。
- \(i - K + 1 \sim i - 1\) 颜色不同:\(dp_i \leftarrow dp_{i - 1} - dp_{i - K + 1}\),相当于要减掉 \(i - K + 1\sim i - 1\) 颜色相同的情况。
\(O(n)\) 递推即可。
AC20 [ABC282G] Similar Permutation(2412)
Atcoder:[ABC282G] Similar Permutation
洛谷:[ABC282G] Similar Permutation
Problem
长为 \(N\) 的排列 \(A\) 与 \(B\) 的相似度被定义为:
- 满足 \((A_{i+1}-A_i)(B_{i+1}-B_i)>0\),其中 \(1\le i<N\) 的 \(i\) 的数量。
求有多少对 \(1\sim N\) 的排列相似度恰为 \(K\),对 \(P\) 取模。
\(2 \le N \le 100, 0 \le K \le N - 1, 10^8 \le P \le 10^9\),\(P\) 是质数。
Solution
好巧不巧,有一道题叫做 Permutation。还有一道题叫做 Deforestation。还有一道题叫做 Zigzag Tree。还有一道题叫做 Maximum Element。这些题都有一个共同的突破点:按 排名 dp。
对于本题,设计 \(f[i][a][b][w]\) 表示两个序列同时填到第 \(i\) 个位置,\(A_i\) 在 \(A\) 的前 \(i\) 个数中排名为 \(a\),\(B_i\) 在 \(B\) 的前 \(i\) 个数中排名为 \(b\),此时的相似度为 \(w\) 的方案数。初始化 \(f[1][1][1][0] = 1\)。
二维前缀和优化即可。根据 Permutation,这道题大概也是可以加强到用多项式来做的?不过暂时还不会。
AC21 [AGC043D] Merge Triplets(2708)
Atcoder:[AGC043D] Merge Triplets
Problem
- 给定如下构造生成长度为 \(3N\) 的排列 \(P\) 的方法:
- 先生成一个长度为 \(3N\) 的排列 \(A\)。然后将 \(\forall k \in [0, N-1]\),\(A_{3k+1},A_{3k+2},A_{3k+3}\) 分成一块。
- 有 \(N\) 个指针,初始指向每个块的第一个数。
- 每次选择所有指针指向的数中最小的数删除,然后放到 \(P\) 的末尾。之后指向被删除的数后移一个位置。若移出块了,则删除这个指针。
- 请你求出,一共能生成长度为 \(3N\) 的排列共多少种。答案可能很大,请求出对 \(M\) 取模的结果。
- \(1 \leq N \leq 2 \times 10^3\),\(10^8\leq M \leq 10^9+7\)。
Solution
直接考虑最终排列,寻找充要条件。
猜到了其中一个条件:把连续下降的数分为一个段,则每段的开头必须单增。
但这样不一定能构造出原排列。有一个超强的 hack:4 3 5 2 6 1
。
这个排列不合法的问题在于,三个二元组是分立的,但是我们只支持两个三元组。
所以另一个条件是:长度为 \(1\) 的段数不小于长度为 \(2\) 的段数,因为这样才能把长度为 \(2\) 的段补成一个完整的三元组。
设计 \(f_{i, j}\) 表示考虑最终排列的前 \(i\) 个位置,长度为 \(1\) 的段数减去长度为 \(2\) 的段数为 \(j\) 的方案数。
讨论下一步段填长度为 \(1 / 2 / 3\) 的段。怎么转移?又是 排名 的思想!
- 下一段长度为 \(1\):则填的数排名一定为 \(i + 1\),\(f_{i + 1, j + 1} \leftarrow f_{i, j}\)。
- 下一段长度为 \(2\):第 \(i + 1\) 个数排名一定为 \(i + 2\),第 \(i + 2\) 个数排名从 \(1 \sim i + 1\) 中任选,\(f_{i + 2, j - 1} \leftarrow f_{i, j} \times (i + 1)\)。
- 下一段长度为 \(3\):类似的,\(f_{i + 3, j} \leftarrow f_{i, j} \times (i + 1) \times (i + 2)\)。
AC22 [ARC065F] シャッフル(2652)
Problem
有一个长度为 \(N\) 的 \(01\) 串 \(S\)。对于每个 \(i=1,2,\ldots,M\),你将要按顺序地进行以下操作:
- 任意地排列 \(S\) 中第 \(l_i\) 到第 \(r_i\) 个字符之间的字符。
请你求出在 \(M\) 次操作后,可以出现多少种不同的 \(01\) 串。答案对 \(10^9+7\) 取模。
保证 \(l_i\) 是不降的。\(N, M \leq 3000\)。
Solution
首先可以把被包含的区间给去掉。
一开始的想法是找到每一个 \(1\) 能到达的最远区间,然后设计 dp 把这些 \(1\) 填上去。但是有些 \(1\) 的位置是相关联的,比如先后进行操作 1 3
,3 10
,并且 \([1, 3]\) 内都是 \(1\),你就不能把三个 \(1\) 全部移到右边去。
实际上可以想得简单一点,设计一个最简单的 dp:\(f_{i, j}\) 表示考虑前 \(i\) 个位置填了 \(j\) 个 \(1\) 的方案数,\(f_{i, j} \leftarrow f_{i - 1, j} + f_{i - 1, j - 1}\)。
我们只需要确定转移时 \(j\) 的上下界即可,这个可以直接模拟解决。
至于洛谷题解区直接以 \(c_{r_i} - (r_i - i)\) 确定上界(及类似地确定下界)的方法,我仍未明白其正确性。
AC23 [ABC301F] Anti-DDoS(2548)
Problem
- 定义形如
DDoS
的序列为类 DDoS 序列,其中DD
表示两个相同的任意大写字母,o
表示任意小写字母,S
表示任意大写字母。 - 给定一个由大小写字母和
?
组成的序列 \(S\),问有多少种将?
替换为大小写字母的方案可以使 \(S\) 不含有任何一个类 DDoS 子序列,答案对 \(998244353\) 取模。 - \(4 \le \left|S\right| \le 3 \times 10^5\)。
Solution
(这部分是错误的)容易设计 dp 状态:\(f_{i, j, 0/1/2/3}\) 表示填了前 \(i\) 位,第 \(i\) 位填了 \(j\),以第 \(i\) 位结尾匹配到了类 DDoS 序列的第 \(0/1/2/3\) 位的方案数。大力讨论转移(方便表示,记 \(c \in U\) 表示 \(c\) 为大写字母,\(c \in L\) 表示 \(c\) 为小写字母,状态后有括号表示转移必须限制的条件):
其中 \(j\) 还必须要与原串能够匹配。
朴素转移是 \(O(n|\Sigma|^2)\) 的,但可以前缀和优化至 \(O(n|\Sigma|)\)。
吗的读错题了。题目要求的是不能出现类 DDoS 的子序列而不是子串。
但是我们还是可以用类似的思想解决子序列的问题。(这部分还是错的)\(f_{i, j, 0 / 1/ 2/ 3}\) 表示填了前 \(i\) 位,最多匹配到了类 DDoS 序列的第 \(t = 0/1/2/3\) 位的方案数。\(j\) 对于 \(t = 1 / 2\) 时表示目前有 \(j\) 种大写字母出现过。以下与 \(j\) 无关的转移将略去对 \(j\) 的书写。
但是还要与原串相匹配,问题来了:如果在原串的当前位置是一个大写字母,我怎么转移?我只记录了之前出现过的大写字母个数,并不清楚具体出现的是哪些字母,所以与 \(1 / 2\) 状态有关的转移都是有问题的。
那怎么才能避免用 \(2^{26}\) 个状态具体记录大写字母的出现情况,又能快速得知类 \(UU\) 子序列的出现情况呢?
正难则反,改变状态的意义,设计 \(f_{i, 2 / 3/ 4}\) 记录填了前 \(i\) 位,没有匹配到类 DDoS 序列的第 \(2 / 3/ 4\) 位的方案数。之前为什么会出现无法转移的情况,就是因为一个大写字母可能出现很多遍,而我不知道某个大写字母是否是第一次出现。而如果反向记录,没有匹配到第 \(2\) 位,那就是每个大写字母最多出现 \(1\) 次,这就好处理了。\(f_{i, 2}\) 甚至可以不用 dp,直接用一个式子算出来:
对于 \(f_{i, 3}, f_{i, 4}\) 可以直接递推,由于式子多但思想简单,这里并不展开。
用另一个角度解读正难则反的可行性,正状态体现的是一种 恰好,必须排除其它状态,而这种排除是难以实现的;反状态体现的是一种 包含,使得状态的转移就像前缀和一样,自然而容易。联想到二项式反演中的常见套路,也是设计 恰好 和 钦定 两种状态,用后者去求解前者。恰好 是一个表观上简洁的事物,但同时也是及其严格的。简单的真理在抽象面前遥不可及。但悲观地说,部分人追求极致简洁的割裂,摒弃了随和而将其视作抽象的厌恶。更悲观地说 —— 至少在这篇文章里,如果没有正状态的设计,我(们?)不过是一片虚无。
AC24 [ABC200F] Minflip Summation(2556)
Problem
给定一个仅含 0
,1
和 ?
的字符串 \(S\) 和一个参数 \(K\),将 \(S\) 复制 \(K\) 次得到字符串 \(T\)。
(即 \(T=SSS...S\),共 \(K\) 个 \(S\))
你可以对 \(T\) 进行若干次操作:每次选取一组 \(l\) 和 \(r\),将 \([l, r]\) 内所有 1
变为 0
,所有 0
变为 1
。求将 \(T\) 中的所有字符变为同一种所需的最小操作次数。
特别地,字符 ?
代表此处还没有填上。?
处既可填 0
亦可填 1
,但你需要将填 0
和 1
的方案都计入最后的贡献之中。
形式化地讲,若 \(S\) 中有 \(q\) 个字符为 ?
,你需要计算所有 \(2^{Kq}\) 种可能的字符串各自所需要的最小操作数,并将它们的总和作为最终答案。
答案对 \(10^9+7\) 取模。\(1 \le |S| \le 10^5, 1 \le K \le 10^9\)。
Solution
首先考虑对于一个确定的 01
序列怎么做。把操作过程看成是逐渐减少 01
段的数量,容易发现每次至多减少一段,所以操作次数应该是 0
段数量与 1
段数量取最小值。如果最终 01
段的数量为 \(cnt\),那么最少操作次数应为 \(\lfloor \frac{cnt}{2} \rfloor\)。
但是 \(T\) 是由很多个 \(S\) 拼在一起的,注意到 \(K\) 很大的范围,应该想到 矩阵乘法。
对于一个 \(S\),做一遍 dp 把矩阵乘法的基底 \(base\) 处理出来,最终 \(base^{K}\) 就能快速得到 \(T\) 的 dp 值。
写一下 dp 转移。记 \(f_{i, 0/1, 0/1}\) 表示到位置 \(i\),位置 \(i\) 填 \(0/1\),并且段数为偶数/奇数时的段数总和。
由于新增一段时,我需要知道要给多少个序列的段数加一,所以还需维护 \(g_{i, 0/1, 0/1}\) 表示表示到位置 \(i\),位置 \(i\) 填 \(0/1\),并且段数为偶数/奇数时的序列方案数。
对于最终段数为偶数的序列最少操作次数和,直接将 \(f_{\dots, \dots, 0}\) 除以 \(2\) 即可。然而对于最终段数为奇数的序列的最少操作次数和,不能简单地将 \(f_{\dots, \dots, 1}\) 除以 \(2\),还要减去 \(\frac{g_{\dots, \dots, 1}}{2}\)。注意这里的 "除以 \(2\)" 都是在乘法逆元下的。
写一下 dp 转移:(需满足原串限制才能转移)
写成 \(8 \times 8\) 的矩阵将 \(f, g\) 包在一起进行转移即可。
为了方便给答案矩阵赋初值,可以考虑把第一个 \(S\) 单独计算,然后再乘上 \(base^{K - 1}\)。
AC25 [AGC050C] Block Game(2528)
Problem
有一个由房间组成的序列,其向左右两端无限延伸。你和 Snuke 在玩下面的游戏:
- 裁判给出一个由
B
和S
组成的字符串 \(t\),名为回合决定串,并将它展示给两名玩家。 - 首先,Snuke 站在其中一个房间里。
- 随后,对于每个 \(i = 1,2,\dots,|t|\),发生如下的事件:
- 如果 \(t\) 中第 \(i\) 个字母为
B
,则这是你的回合。你会选择一个其中即没有障碍也没有 Snuke 的房间,在其中放置一个障碍。这之后,如果 Snuke 所在房间左右两侧的房间均放置有障碍,则你胜利,游戏结束。 - 如果 \(t\) 中第 \(i\) 个字母为
S
,则这是 Snuke 的回合。他可以移动到与当前所在房间相邻且无障碍的房间,或什么都不做。
- 如果 \(t\) 中第 \(i\) 个字母为
- 如果 \(|t|\) 轮后游戏仍未结束,则 Snuke 胜利,游戏结束。
给定字符串 \(s\),其中仅含有 B
、S
与 ?
三种字符。设 \(s\) 中含有 \(q\) 个 ?
,有 \(2^q\) 种填法将 \(s\) 中的 ?
替换为 B
或 S
,得到一个回合决定串。假设两名玩家都按最优策略操作,在这 \(2^q\) 个串中,有多少种填法使得你能胜利呢?
请输出答案模 \(998244353\) 的值。\(1\le |s|\le 10^6\)。
Solution
你可以在中途的某些位置赢,但 Snuke 只能在末尾赢,所以我们不妨考虑 Snuke 怎么赢,并用总数减去使得 Snuke 赢的方案数。
假设序列形似 \(SS\dots SSBSS\dots SSBSS\dots SSB\dots SSBSS\dots SS\),从前往后 \(S\) 段的大小分别为 \(a, b, c, d, e\),第一段显然是没用的,我们直接从第一个 \(B\) 开始看:Snuke 尽可能地远离第一个 \(B\) 放置的位置,到下一个 \(B\) 放置时,他可以扩充一个 \(b + 1\) 的区间。
然后又轮到 Snuke 移动。Snuke 的策略是尽量向中间移动,模拟一下可知,Snuke 的下一个可移动区间长度为 \(\min(\lfloor \frac{b}{2} \rfloor, c) + 1\)。
同理,对于接下来的操作,Snuke 的可移动区间长度为 \(\min(\lfloor \frac{b}{4} \rfloor, \lfloor \frac{c}{2} \rfloor, d) + 1\)。(\(\lfloor \frac{\lfloor \frac{b}{2} \rfloor}{2} \rfloor = \lfloor \frac{b}{4} \rfloor\))
若在结束前 Snuke 的移动区间长度为 \(1\),说明他就无法移动了,Snuke 也就输了。
所以 Snuke 赢的条件是:从右往左第 \(i\) 个 \(B\) 左边的 \(S\) 区间长度 \(\ge 2^{i - 1}\)。(不考虑左右端的 \(S\) 段)
设计 \(f_{i, j}\) 表示(从右往左填)到 \(i\) 时出现了 \(j\) 个 \(B\) 的合法方案数,\(f_{i, j}\) 根据 \(j\) 的限制进行转移。
这个转移和上面的 At Most 2 Colors 有异曲同工之妙,强行钦定一段连续的区间填一个元素,由这段区间前的 dp 值进行转移。
时间复杂度 \(O(n\log{n})\)。