「题集」精致的袖珍题目-2021 年度

「NOIP2008 提高组」双栈排序

题目链接:洛谷


考虑两个位置不能被放入同一个栈中的条件。

通过多次手玩可以发现,如果有 \(i<j<k,a_k<a_i<a_j\),则 \(i,j\) 不能被放入同一个栈中。

\(a_i<a_j\) 要求 \(i\) 先于 \(j\) 出栈,但是 \(i\) 想要出栈就必须要 \(j\) 入栈,所以 \(j\) 要先于 \(i\) 出栈,因此矛盾。


一定要注意这个 \(k\) 的存在,才能保证 \(j\) 必须要进栈。

现在我们有两个栈,这就说明我们需要将所有位置分到两个集合当中,满足每个集合中元素两两不冲突。分集合可以看作对点染色,而染色的要求就是,对于任意一对冲突的 \((i,j)\)\(i,j\) 颜色不同。不难发现这是将所有的 \((i,j)\) 当作边加入图中后,对图进行黑白染色,模拟操作即可。如果不存在染色方案,那么就应该输出 0。

假如我们知道了染色方案,我们可以贪心地构造出操作序列——只需要每一轮贪心地选取字典序最小的合法操作即可。操作序列中 a 的位置由染色方案限制,因此我们需要尽量让较小的位置可以被放入第一个栈中,贪心地染色即可。

小结:

  1. 对于重要结论,一定保证正确,不能缺漏或者不完整。一定要用多种数据来检查,最好可以给出严谨的说明/推导!
  2. 注意将问题转化到图上这种研究方式,直观清晰;转化看对象的角度常常是有效的。

「CF1064D/CF1063B」Labyrinth

题目链接:CF洛谷


\((x_0,y_0)\) 出发到达 \((x_1,y_1)\) 的时候,可以发现向左/向右的次数必然满足一条等式关系:

\[x_1-x_0=R-L \]

那么只需要最小化其中一个量即可。

小结:

注意隐含条件:如果遇到多个变量的问题不方便转化,不妨入手看看特定情况下(某些信息枚举/推算之后)有没有变量之间的关系

「CF877D」Olya and Energy Drinks

题目链接:CF洛谷


每个位置在行和在列上可以到达的位置是一段区间,因此我们可以使用 set 维护每一行、每一列上未被遍历的位置

小结:这里利用了 BFS 的特性(每个点只需要被遍历到一次),同时也利用了图的特性。注意使用数据结构维护有效点的方法

使用线段树优化建图 +0/1BFS 应该也有正确的复杂度,不知道为啥过不了。

「CodeChef20May」双色城

题目链接:Vjudge


容易发现两行之间的转移可以用矩阵来描述,那么我们需要维护的是从第一行到最后一行的矩阵的乘法(或者也可以看作是 DP 数组)。

矩阵的乘法的性质就是“可加而难减,具有结合律”,此处我们可以双栈模拟队列规避矩阵求逆,可以做到 \(O(qn^2)\)

小结:注意双栈模拟队列的技巧,它可以用来维护队列中具有结合律、容易加而不易减的信息,例如 \(\min,\max\) 和矩阵乘法。

「CF23C」Oranges and Apples

题目链接:洛谷


如果我们只考虑其中一种水果满足要求,那么排序之后取前 \(n\) 大的即可。

现在需要两种水果都满足要求,那么容易想到一种方向:由于一共有 \(2n-1\) 个盒子,取出一个之后,剩下的正好可以分出 \(n-1\) 组,每组里面有两个;我们可以从每组中选取一个,加上最初取出来的那一个,得到了一种方案;

结合前面的想法,我们可以将盒子按照苹果排序,有最多苹果的盒子单独取出来,剩下的相邻两个盒子分在一组。而后,每组中我们选取橘子数目较多的那一个。这样优先保证组内选取时苹果的差距较小,而后最大化橘子数目。

考虑证明这种选法的正确性:

设排序后,第 \(i\) 个盒子内苹果数量为 \(a_i\),橘子数量为 \(o_i\);我们的分组方案会将 \(i\)\(i+1\) 分为一组,其中 \(i=2k,1\le k<n\)

根据条件,同一组内 \(a_i\le a_{i+1}\);所以考虑 \(a\) 最小的选取方案,我们会选择奇数位的盒子,此时一一跨组对应有 \(a_i\ge a_{i-1},i=2k+1\),同时 \(a_1\ge 0\),所以一定有 \(\sum_{k=0}^{n-1}a_{2k+1}\ge\sum_{k=1}^{n-1}a_{2k}\),因此苹果数保证不少于一半。

考虑橘子,同一组内,选取的 \(o\) 一定不会小于同一组内另外一个,类似地得出橘子数也保证不少于一半。

小结:注意题设条件的一些细节,比如\(2n-1\) 中选出 \(n\) 个,恰好比一半多 1,比如最终两种元素的和都保证不少于一半,这些信息都提示我们要考虑一一对应、考虑按照 2 的大小来分组;组合数学的基本方法要掌握!

「CodeChef18Feb」Points Inside A Polygon

题目链接:Vjudge


注意到凸多边形的一个性质,任意两点的连线都包含在多边形内部。所以我们可以尝试在顶点的连线上寻找格点。

一种巧妙的构造方法是,我们尝试选取凸多边形上的中点;中点在格点上的条件为起点终点在 \(x,y\) 两维上坐标同奇偶。根据这个信息我们可以划分 4 个抽屉,每个点必然属于其中一个抽屉,因此必然有一个抽屉中有 \(\lceil\frac{n}{4}\rceil\) 个点。这样可以构造出不少于 \(\frac{n^2}{16}\) 个点(需要判重),基本上是足够了。

小结:注意抽屉原理的运用

一段数学推导

求解下面这个式子的结果:

\[\sum_{j=0}^{n}\binom{j}{k}\binom{n-j}{m-k} \]

满足 \(n\ge m\ge k\ge 0\)


注意到上指标变动,这种形式出现在 \(\frac{1}{(1-x)^p},p\ge 0\) 的系数中,因此我们可以通过生成函数推导:

\[\binom{j}{k}=\frac{x^k}{(1-x)^{k+1}}[x^j]\\ \binom{n-j}{m-k}=\frac{x^{m-k}}{(1-x)^{m-k+1}}[x^{n-j}]\\ \sum_{j=0}^n\binom{j}{k}\binom{n-j}{m-k}=[x^n]\frac{x^m}{(1-x)^{m+2}}=\binom{n+1}{m+1} \]

小结:下指标变动求和我们可以尝试范德蒙德卷积,上指标变动我们就应该尝试生成函数了!对这样的基础结构应该要熟悉!

「LibreOJ β Round」ZQC 的手办

题目链接:LOJ


考虑一个暴力的做法:每次取出区间内的最小值,判断是否符合要求;如果符合要求就删除它,不符合要求就判断数量是否足够;最后我们需要将所有操作撤销,也就是将所有删除了的数加回去。

这些操作都可以用线段树方便地完成,删除即赋 \(+\infty\),撤销只需要记录哪些被删除了;由于我们只会取出最小值,因此我们只需要针对最小值打标记——记录区间内的最小值变成了什么。

另一种更巧妙的做法是,原先询问区间为 \([l,r]\),取出位于 \(p\) 的最小值之后,区间由于不能再包含 \(p\),就相当于分裂成了 \([l,p)\)\((p,r]\);因此我们可以用堆维护当前所有有效区间,每次取出区间最小值最小的区间,操作完后继续拆分即可。这样每次最多增加一个区间,可以保证复杂度。

小结:

  1. 查询前 \(k\) 小的通用方法:取 \(k\) 次最小值;
  2. 注意将集合的减法变成加法的操作,对于易于合并而难以删除的信息有效;该方法在「NOI2010」超级钢琴中也有使用。

「CF867E」Buy Low Sell High

题目链接:CF


考虑一个比较显然的错误做法:每天都尝试卖股票,同时在此之前需要有一天来买好股票,所以我们用一个堆维护价值最低且尚未被买入的一天来买入(如果那一天也在卖股票,一买一卖相当于休息一天);如果发现当天卖倒贴钱,就不卖了。

但是这个做法有误,考虑如下数据:

4
1 2 4 5

该算法会给出“第一天买入第四天卖出”的方案,而最优的方案是“第一第二天买入,第三第四天卖出”。

问题在于,如果某一天的股票被作为中间量抵消了,那么它可以被再次入手。因此我们可以将同一天的价格入堆两次,第一次表示换股票,第二次表示买股票。

小结:

  1. 贪心算法往往是在试错中成功,因此不要怕想出错算法,找出错才能修正!
  2. 重复入堆的想法比较巧妙,能否借鉴?

「APIO2007」数据备份

题目链接:洛谷


最优方案中一定是相邻的两个办公楼配对,因此可以设 \(d_i\)\(i\)\(i+1\) 之间的距离。由于办公楼不能被多次配对,问题相当于变成了求 \(d\) 中不相邻 \(k\) 个数的最小和。

考虑一个贪心:每次选出最小的 \(d\),并删除相邻的。显然这个贪心是错误的,样例都过不了。但是考虑,出错的原因是方案并不完全可以增量构造。如果 \(d_k\) 在方案中,我们同样可以选择删除 \(d_k\) 而加入 \(d_{k-1}\)\(d_{k+1}\)。相似地,如果用 x 表示选中,o 表示不选中,我们可以将方案由 oooxoxoxoxoo 变为 ooxoxoxoxoxo,这样“取反”可以增大选择个数,同时保证不相邻。

因此加入反悔选项,用一个堆来维护当前的最小增量的选项;此外需要用链表来维护尚未被确定的点。实现有许多巧妙的地方,比如我们可以直接访问一个连续段的中心来处理两个反悔选项合并的情况。建议阅读代码。

小结:贪心过程中如果出现了某些方案被忽略的情况,同时容易被快速构造出来,就可以尝试反悔

「ABC131F」Must Be Rectangular!

题目链接:AT


我觉得暴力 bitset 什么的很有机会

一种经典的转化方式:按照行、列建成二分图,点 \((a,b)\) 就相当于在行 \(a\) 与列 \(b\) 之间连边。

考虑题目中给定的操作,就相当于:当左部的某个子集和右部的某个子集已经连通时,就将这个子图补成完全二分图:

ABC131F.png

计算每个连通二分图内部的左部、右部点数即可,并查集/DFS 什么的都可以解决。

小结:注意一下将点看作连边构建二分图的方式,比较巧妙(和常见);同时转化条件要足够简洁。

「PMOI-4」可怜的团主

题目链接:洛谷


比较简单的二选一构造题。考虑树的情况,由于路径覆盖限制很松(只要求每个点被覆盖到一次以上、路径无环且不同),并且叶子一定要被覆盖到,树上的最少路径数量一定是 \(\lceil\frac{\text{叶子数量}}{2}\rceil\)。这一步构造非常经典,此处略去不讲了。

\(l\) 为叶子数量,首先我们应该关注独立集,如果 \(l\ge \lfloor\frac n 3\rfloor\),叶子已经构成了所需的独立集;反之,\(l<\lfloor\frac n 3\rfloor\),那么一定有 \(\lceil\frac l 2\rceil\le \lceil\frac n 6\rceil\)

尝试拓展到一般的简单连通无向图,我们可以构建 DFS 树,这样可以保证非树边均为返祖边,那么 DFS 树的叶子之间也就不会连边。需要注意,虽然根有可能度数也为 1,但是我们不能保证根和其它叶子没有边连接,所以我们考虑叶子的时候总不加入根;而构造路径的时候,度为 1 的根则会影响结果,所以我们可以考虑路径的时候总加入根

小结:

  1. 树上的问题大多可以从特殊点入手,包括但不限于根、重心,叶子......
  2. 一定要注意,拓展问题的时候要尽量考虑简单的修改,而不要快速地加入太多繁杂的修正,这样既容易搅乱思路,也容易掉入怪圈。思维保有简洁的连贯性

「ABC216G」01Sequence

题目链接:AT


容易看出是差分约束,\(s_i\) 为前缀 \([1,i]\) 的和,考虑每一条约束条件

\[\begin{cases} s_{i+1}\ge s_i,i\in [0,n)\\ s_i+1\ge s_{i+1},i\in [0,n)\\ s_{R_k}-X_k\ge s_{L_k-1},k\in [1,m] \end{cases} \]

建图的时候,会有源点向每个点连接权为 0 的边。不过由于 \(s_{i+1}\ge s_i\) 的限制,从 \(s_n\) 开始跑最短路效果一样。

注意到,如果去掉 \(s_i+1\ge s_{i+1}\),原图是 DAG。而由于图上不存在负环,对于一条由 \(s_{R_k}-X_k\ge s_{L_k-1}\) 构造出来的边,它不会影响到 \(R_k\) 及编号更大的点。因此,我们可以按照原顺序算 \(s\),但是需要动态地处理 \(s_i\) 对于标号大于 \(i\) 的点的贡献,使用树状数组就可以了。

小结:

  1. 差分约束系统学得不好啊,最开始一直没想到 \(s_{i+1}\ge s_i\) 形态的限制,然后又没有想起来“源点向每个点连一条 0 边”的操作,卡了半天其实是连图都不知道怎么建!
  2. 注意一下对于这样的特殊图计算最短路的方法,这里主要的想法是“维护某一类边的贡献、剩下的当作最短路来算”。

「ARC084B」Small Multiple

题目链接:AT


枚举 \(K\) 的倍数是困难的,但是枚举一个数本身是简单的。我们可以通过某种方式枚举数,并且记录 \(\bmod K=0\) 的数的最小数码和。

十进制的正数有一种简单的枚举方式:从 1 开始,每次取出一个已经被遍历、还没有被扩展的数,而后可以将它 \(\times 10\);如果它末尾小于 9,也可以将它 \(+1\),将两种情况的结果都放入已有的数集里面。可以发现,这样每个数会且仅会被枚举一次。

同时,这种枚举方法很容易计算数码和:将 \(+1\) 的权设为 1,将 \(\times 10\) 的权设为 0。我们不需要关心某个数的末尾值,因为如果 \(+1\) 使得个位“超过” 10,那么这样肯定不会优于 \(\times 10+1\)。所以,从 1 出发到每个数的最短路就是那个数的数码和。

小结:

  1. 放宽限制,枚举 \(K\) 的倍数就是枚举所有数,再考虑 \(\bmod K=0\) 的结果;
  2. 注意这种巧妙的枚举数的方式,这是从递归的角度来构造整数集的。

「CF1473E」Minimum Path

题目链接:CF


注意到 \(\max\)\(\min\) 本身所带的“极值”属性:假如我们可以任选路径上的一条边去除代价,那么选取 \(\max\) 一定是最优的;如果必须任选路径上的一条边加上代价,那么选取 \(\min\) 一定是最优的。

因此,我们可以放宽问题的范围,只需要算那些“选了一条边删”和“选了一条边重复”的最短路即可。

小结:放缩问题而保持最值不变,这是非常常见的处理技巧。需要注意的是,一般而言放缩的东西就和最值有关,而这个最值应该是和最终所求的最值是同向的。

「CF741C」Arpa’s overnight party and Mehrdad’s silent entering

题目链接:CF


要求“任意相邻三个人的食物不同”其实就是说某个人左边和右边中一定有一个和他食物不同

在不考虑男女朋友限制的情况下,我们可以分配 \(2k-1,2k\) 的食物不同。想象成二染色问题,我们可以建立图。

现在再考虑关系限制:这其实就是要在每一对男女朋友之间额外连一条边。注意到,新图不可能存在奇环,因此二染色之后即可得到答案。

考虑第一种边为 A 边,第二种边为 B 边。

这两种边都有特性:单独考虑 A 边或者 B 边,它们一定构成了一组匹配

所以原图如果有环,那么 A 边后面一定是一条 B 边,B 边后面一定是一条 A 边。这样配对,则一定只有偶数条边。

小结:最开始的某些人为的限制(比如要求 \(2k-1\)\(2k\) 食物不同),可以帮助简化问题。

「UVA1397」The Teacher's Side of Math

题目链接:洛谷


没什么可说的,二项式定理展开对应项的系数即可。

需要注意的是,因为题设条件保证最终可以解出来整数的多项式,因此直接拿 double 消元就可以了,可以避免不少讨论。

「ARC127C」Binary String

题目链接:AT


注意到,暴力退位的复杂度最终会是 \(O(N)\) 的,因为每当第 \(k\) 位被退了之后,低 \(k\) 位全部变成了 1,这样下一次碰到第 \(k\) 位退位至少是 \(2^k\) 步之后了。这样总复杂度为:

\[\sum_{k\ge 0}\lfloor\frac n {2^k}\rfloor=O(n) \]

相似地,有一个结论是,在二进制下,如果从 0 开始,按笔算方式一步一步 +1 直到 \(n\),那么总的进位次数也是 \(O(n)\) 的。

某个经典问题

给定一张二分图,左侧有 \(n\) 个结点,右侧有 \(m\) 个结点,共有 \(k\) 条边。现将图上的每条边染成 \([1,c]\) 中的某种颜色,染色后,一个点的代价为与它相连的边中出现最多的颜色数和出现最少的颜色数之差。找出一种方案,使得代价之和最小。


首先可以分析问题的下界:如果一个点的度数为 \(c\) 的倍数,那么最优情况下它不会贡献代价;否则,它至少要贡献 1 的代价。那么就不难算出一个下界为:

\[\sum_u [d_u\bmod c\not =0] \]

然后通过暴力验证发现这多半就是答案。我们可以尝试构造出一组合法的方案。

一种构造方法是,我们可以想到,将一个点的任意 \(c\) 条颜色不同的边打包看成一组,并且拆分成一个新的点。这样一个点就被分成了 \(\lfloor\frac d c\rfloor\) 个度为 \(c\) 的点和一个度数 \(d\bmod c\) 的点。按照我们的要求,现在任何一个点的邻边颜色不同,这就是边染色的问题。根据 Vizing 定理,二分图的最大度数为 \(c\),因此这个边染色是可以做到的。

小结:体会一下分组思想,了解一下 Vizing 定理

「CF1326E」Bombs

题目链接:洛谷CF


思考过程中有两点需要注意:

  1. 处理问题需要多方面入手。为什么必须“从前往后”而不能想到“从后往前”呢?思维不要局限了;
  2. 适当地转化为常见的模型。本题中可以转化到括号匹配的模型上,更加易于思考。

关于 BFS 的优化

在边数远远大于点数的时候,我们可以通过避免重复访问的方法来降低复杂度。

例如,当我们需要求两两最短路时,直接 BFS 复杂度为 \(O(nm)\)。但是,当图比较稠密的时候,很有可能几步搜索后每个点就已经被更新好了,如果再根据边来搜索点就非常低效。一种有效的处理方法是,使用 bitset 维护好邻接未遍历点集,这样可以保证每一步拓广都是有效的,复杂度可以降到 \(O(\frac{n^3}{\omega}+m)\)

话说,模拟赛的这道题目数据太水,直接用链表维护也过了。

「CF53E」Dead Ends

题目链接:CF洛谷


着重讲一下如何去重。

仔细分析可以发现,重复计算是因为从同一个点扩展时的边会出现定序的问题。如果不加限制,那么就会因为顺序不同而算重。显然的去重方法就是转移的时候钦定顺序

假如我们确定了根,那么构造的过程可以看作按照 BFS 顺序生成这棵树。一种方法是,我们总保证加入的叶子是加入后叶子集合中最大的,那么这我也不知道怎么就可以保证每棵树只被计算一次。

「USACO04JAN」有序奶牛

题目链接:DarkBZOJ


题目就是要求我们简化有向图,使得图对应的偏序关系(对应可达性)不改变。

考虑暴力枚举边并判断连通性,从而确定某条边是否可以被删除。这样我们需要确定一个顺序。交换论证可以说明,当终点按照拓扑序从小到大,相同时按照起点拓扑序从大到小排序是最优的。使用 bitset 判断连通性即可。

「WC2010」重建计划

题目链接:洛谷


注意一下,如果直接使用单调队列会出问题。复杂度分析出来是 \(\max\{dep_{\max},dep_{\operatorname{cur}}\}\)。如果 \(dep_{\max}\) 不幸地出现在了首位,并且比较大,并且子树比较多,并且数据被精心构造,那么就会被卡掉。

解决办法是人为控制顺序,排个序让 \(dep_{\max}\) 靠后出现,也就是按照 \(dep\) 从浅到深排序即可。

总结:准确分析复杂度,同时复杂度也可以指导优化方向,也就是规避糟糕的情况或者减小碰到的概率。


一段补充:在点分治过程中做单调队列都是这个复杂度,因此在点分治上单调队列一定要注意按照深度从小到大处理,才能保证复杂度为 \(O(\sum dep_{\operatorname{cur}})\)

「CodeChef18Jun」 Archi and Tree

题目链接:Vjudge


容易发现,问题相当于在树上的一条路径上覆盖一个一次函数,最终需要对于每个点,求出覆盖到它的一次函数在它那里能取到的最小值。

容易想到树剖后维护李超树的算法,但时间复杂度是 \(O(n\log^3n)\) 的,目测难以通过。

另外一种想法是,注意到询问在修改之后才进行,我们可以使用倍增维护标记。此外,由于李超树本身只依赖于决策单调性和分治结构,因此在倍增对应的结构上,“李超树”也是可以被维护的。

最后就只需要在全部修改结束后,从长到短下放标记信息即可。

复杂度瓶颈在下放,最终复杂度为 \(O(n\log^2n)\)

「CF1383A」String Transformation 1

题目链接:CF


研究最值问题,一种方法是去分析上下界当然应当先得到正确的问题

比如此题,我们可以把转移关系变成图 \(G_1\)。我们需要得到一个 \(G_2\),使得 \(G_2\) 上偏序关系是 \(G_1\)超集,且 \(G_2\) 上具有最少的边。

分析下界——若图上有 \(n\)连通块,则下界是 \(26-n\),因为每个大小为 \(S\) 的弱连通块内部需要至少 \(S-1\) 条边才可以保证弱连通,否则一定和 \(G_1\) 不同。

另一方面,我们发现我们也可以构造出一种方案——按照每个弱连通块内的拓扑序构造一条链即可。因此这个下界可以被取到。

「CodeJam21 R3」Square Free

题目大意:给定一个 \(n\times m\) 的方格,要求在每个格子里放入左斜杠 / 或者右斜杠 \。每一行和每一列的斜杠数是预先确定的。此外,还要满足不能存在斜杠构成的斜正方形。求一种构造方案。

下面两种方案中都含有斜正方形:

\///
/\\/
///\
//\/
----
//\\
//\\
\///
/\//

对于 \(100\%\) 的数据,满足 \(1\le n,m\le 20\)


主要体现的是调整的思想

我们可以先随便构造出一种符合数量限制的方案。此时这个方案中可能存在正方形,我们就需要调整方案——将它们破坏掉。注意到正方形是一个数量上行列都对称的图形,每一行、每一列上所包含的正方形上的左斜杠数就等于右斜杠数。因此,我们可以将 /\ 对换,从而消去这个正方形。如果还有正方形,继续这个过程。

假设 / 的字典序大于 \,那么破坏正方形的时候,整个方案的字典序会变小,因此调整过程一定会结束。更进一步,字典序最小的方案中一定不含任何正方形,因此我们去求出这样一个方案即可。

总结:注意调整思想,观察图像性质

「HDU 6623」Minimal Power of Prime

题目链接:HDU


如果暴力分解肯定过不了,即便用升级过的算法。

但是,我们可以先筛掉小范围的质因子。假设经过这个过程后,我们得到了 \(n'\),那么对 \(n'\) 分解得到 \(\prod_k p_k^{e_k}\)则一定有 \(p_k>\sqrt[5]{n}\),也即 \(e_k\le 4\)

这样的话,情况就减少了许多。由于我们只关心指数,因此值得考虑的情况只有 \(n'=a^4,n'=b^3,n'=c^2,n'=x^2y^2\) 这五种情况,直接开根计算即可。

总结:处理大数分解或者大范围筛法的时候,一定要利用要小范围筛大范围这种方法

「FJOI2016」建筑师

求长度为 \(n\) 的排列中,前缀最大值有 \(A\) 种,后缀最大值有 \(B\) 种的排列个数。

对于 \(100\%\) 的数据,满足 \(1\le n\le 5\times 10^4, 1\le A,B\le 200\)


首先注意到 \(n\) 一定会在前缀最大值和后缀最大值中分别被算到一次。假设 \(n\) 在排列 \(p\) 中出现位置为 \(k\),那么我们只需要让 \([1,k)\) 中出现 \(A-1\) 种前缀最大值,\((k,n]\) 中出现 \(B-1\) 种后缀最大值即可。

对于排列按照前缀最大值/后缀最大值划分组,使得每一组在排列上是一段区间,且要么左端点对应一个前缀最大值、要么右端点对应一个后缀最大值。因此,在组内元素确定的时候,一个大小为 \(s\) 的组对于答案的贡献为 \((s-1)!\)

考虑每一组的元素确定,并且组内的顺序也已经确定的情况。由于 \([1,k)\)\((k,n]\) 的任意一侧,只要确定了最终的组的划分方案,就可以按照最大值进行排列,并且这是唯一的方法;因此,仅仅有每组属于的侧边会影响方案,方案数就是 \(\dbinom{A+B-2}{A-1}\)

考虑到组内方案数为 \((s-1)!\),这其实就是确定元素后 \(s\) 个元素进行环排列的方案数。换言之,在这里对应 \(\begin{bmatrix}n-1\\A+B-2\end{bmatrix}\)。因此最终的答案为 \(\begin{bmatrix}n-1\\A+B-2\end{bmatrix}\dbinom{A+B-2}{A}\)

小结:关注划分的建构模型的方法,注意建立一一映射的思想,从而转化所求对象

「HDU」DZY Loves Math IV

求:

\[\sum_{i=1}^n\sum_{j=1}^m\varphi(ij)\bmod (10^9+7) \]

其中有 \(1\le n\le 10^5,1\le m\le 10^9\)


一种常见的思路是,将 \(\varphi(ij)\) 拆分为 \(\varphi(i)\varphi(j)\cdot \frac{\gcd(i,j)}{\varphi[\gcd(i,j)]}\),然后直接走莫比乌斯反演——但是实际上,反演过后我们面临的不是形式简单的子问题,而是结构一致的子问题。总而言之,就是问题并没有变简单。

回顾以上思路,我们发现问题出在\(n\)\(m\) 同等对待了,而题目的数据范围已经在明确暗示 \(n\)\(m\) 的地位实际上并不相同。因此,我们不妨先研究一个子问题:

\[\renewcommand{\div}[2]{\lfloor\frac{#1}{#2}\rfloor} \begin{aligned} S_n(m) &=\sum_{i=1}^m\varphi(ni)\\ &=\sum_{i=1}^m\varphi(n)\varphi(i)\cdot\frac{\gcd(n,i)}{\varphi[\gcd(n,i)]}\\ &=\varphi(n)\sum_{d|n}\frac{d}{\varphi(d)}\sum_{i=1}^m\varphi(i)[\gcd(n,i)=d]\\ &=\varphi(n)\sum_{d|n}\frac{d}{\varphi(d)}\sum_{d|k|n}\mu(\frac{k}{d})\sum_{i=1}^{\div{m}{k}}\varphi(ik)\\ &=\varphi(n)\sum_{k|n}S_k(\div m k)\sum_{d|k}\mu(\frac k d)\frac{d}{\varphi(d)} \end{aligned} \]

注意到我们已经得到了相似的、可以递归的子问题,递归的边界是 \(S_1(m)=\sum_{i=1}^m\varphi(i)\),使用杜教筛可以在 \(O(m^{\frac 2 3})\) 的时间内算出所有需要的点值。

那么最终所求的就是 \(\sum_{i=1}^nS_i(m)\)。经过记忆化之后可以得到复杂度为 \(O(nm^\frac 1 2+m^\frac 2 3)\) 的算法。但具体怎么分析出来的我也不清楚

小结:

  1. 关注细节,充分利用题目的特殊性,用好特殊的数据范围。
  2. 此处研究 \(S_n(m)\) 的方向比较常见,也就是尝试将原问题化归到较小规模的子问题并进行递归,期间可能会用到整除分块之类的优化策略。
posted @ 2021-08-10 19:07  crashed  阅读(255)  评论(0编辑  收藏  举报