A.
不难发现,当且仅当数组中只由一个数组成时,才满足题目要求。所以输出 即可。
B.
对于一个长度大于 的子串
,设
出现的位置是
,如果存在一个不连续的子序列等于
,那么以下两条有至少一条成立:
- 存在
使得
;
- 存在
使得
。
并且我们发现这个条件也排除了 作为子串出现多次的情况,所以只需要找到所有字母第一次出现位置的集合
,以及所有字母最后一次出现位置的集合
,答案就是
。
C.
把 看作左括号,
看作右括号,如果
不是合法括号序列,答案就一定是
。
把括号树建出来,每一次操作会删掉一个叶子以及它的父亲,如果它的父亲有多于一个儿子,答案也是 。
所以我们可以每次把一个叶子和它的父亲合并起来,然后在新树上建一个点,表示同时删掉这个叶子和它的父亲。在这棵新树上,能做的操作就是每次删去一个叶子。所以问题变成了树的拓扑序计数,根据经典结论,答案是 。
D.
首先,如果预先将 数组排序,那么操作后
仍然是有序的。
考虑用数据结构维护 中奇偶性相同的连续段。对于一次操作,先在数据结构上求出需要操作的下标区间
,然后枚举
中的所有连续段,进行操作。因为操作后
会变成一个连续段,所以均摊时间复杂度是对的。
维护连续段可以用 std::map
,维护 数组可以用线段树。时间复杂度
。std 直接在线段树上做连续段均摊,会好写一些。
E.
我们给 赋予一个组合意义:从
间路径上选择一条边的方案数。
所以可以直接做树上 DP,设 表示:考虑
子树内的所有点,总共有
个点还没有配对,其中
个点没有选择边,
个点选择了边,的方案数。
对于 的一个儿子
,考虑如何合并
和
:枚举
表示:总共新增了
对点,其中
对选择的边在
这边,
对选择的边在
这边。
根据树上背包的时间复杂度分析,这样做的时间复杂度是 。
F.
考虑这个限制:
对任意
,存在
,满足
或
。
对它容斥,钦定有 个位置
满足:
- 不存在
使得
或
;
- 不存在
使得
或
。
注意到容斥后两维是独立的,我们可以对两维分别算出钦定 个位置不合法的方案数,然后乘上一些系数将它们组合起来。
设 表示在长为
的序列中选择
个位置,且钦定其中
个被选择的位置
满足
和
都没被选择的方案数,那么答案为:
其中两个阶乘的意义是,那些钦定不合法的 个位置可以任意配对,剩下
个位置可以任意配对。
于是只需要考虑如何快速对于每个 ,算出
。注意到固定所有钦定不合法的位置以后,假如有
个空位满足与它相邻的位置都没被钦定,那么这样一种方案对
的贡献是
。
于是转而对于每对 ,计算有多少种钦定的方式。设
个变量
,其中
表示从小到大第
个被钦定的位置到上一个被钦定位置的距离,如果
则表示它到开头的距离。有:
;
;
;
- 空位个数为
。
添加变量 ,做一些转化:
;
;
- 空位个数为
。
固定 个
,设
,则有
个空位的方案数是:
为了方便,设 。则
于是我们可以 计算一个
,原式可以在
时间复杂度内计算。总时间复杂度
。
G.
考虑每个质数 ,只需要算出来有多少个
使得
,设这个数是
,答案就是
前面的组合数之积是好算的,所以只需要快速算出所有 即可。
先考虑一个 怎么算。根据 Kummer 定理,
在
中的幂次,就是在
进制下把
和
加起来的过程中,产生进位的次数。所以我们不妨算
的情况,也就是,在
进制下
和
的每一位加起来都要小于
。
记 。对于
的情况,这样的
的数量可以用数位 DP 算。这部分的时间复杂度是
。
对于 的情况,
在
进制下至多只有两位,而
在
进制下只有一位。不妨将
代换成
,我们要算有多少个
满足
。这样的
的个数显然是两部分加起来:
;
。
第一部分是好算的,直接整除分块即可;考虑第二部分中,什么时候 。推一下发现是
,设
,也就(大约)是
,也就是说,这种特殊的
的取值范围的大小只有
,对所有
求和,总的大小只有
。对于这些
暴力算,剩下的
仍然能整除分块。
精细实现,时间复杂度 。
全部评论
(2) 回帖