8.2
上午
动态规划
例题(部分还没理解,仅是题解)
Gcd Counting
题目描述
给出⼀棵n个节点的树, 每个节点上有点权a_i。
求最⻓的树上路径, 满⾜条件:
路径上经过节点(包括两个端点) 点权的gcd和不等于1。
数据范围
n <= 2 * 10^5
1 <= a_i <= 2 * 10^5
不互素就不⽤考虑具体的gcd值, 也不⽤考虑重复计算。
对于每个节点u, 维护dp_{u,v}表示u往下挂出的点权都能被v整除的最⻓链。
v只取整除a_u的质数, 个数很少, 很容易转移。
边转移边更新全局答案。
You are given a tree
题目描述
给出⼀棵n个节点的树, 对于1~n间的每⼀个数k, 你需要求出:
最多能选出多少条互不相交的路径, 每条路径的⻓度都为k。
数据范围
n <= 10^5
考虑对于⼀个给定的k, 使⽤dp计算答案。
贪⼼: 在⼀个⼦树当中, 尽可能最⼤化完整的路径条数; 其次最⼤化未完成的链的⻓度。
进⾏合并时, 先尝试⼉⼦的dp值中第⼆维最⼤值与次⼤值能否拼成⼀条完整的链(⻓度和>=k) , 若不⾏再选取⼀条最⻓的链向上延伸。时间复杂度为O(n)。
令f[k]表示单次对于给定的k的答案。 显然有: f[k] <= n / k
f 中不同的取值个数是 O ( n ) \mathcal{O}(\sqrt{n}) O(n)级别的!
⼜因为 f 显然单调,所以在每个边界上⼆分即可。
时间复杂度为 O ( n n log n ) \mathcal{O}(n \sqrt{n} \log n) O(nnlogn)
Vladislav and a Great Legend
题目描述
给出⼀棵n个节点的树T。
对于其中任意⼀个⾮空节点集合X, 定义f(X)为包含这些点的最⼩连通⼦树的边数。
给出⼀个正整数k, 求: ∑ X ⊆ { 1 , 2 , … , n } , X ≠ ∅ ( f ( X ) ) k \sum_{X \subseteq\{1,2, \ldots, n\}, X \neq \varnothing}(f(X))^{k} X⊆{1,2,…,n},X̸=∅∑(f(X))k
答案对10^9+7 取模。
数据范围
2 <= n <= 10^5.
1 <= k <= 200.
其中S(k,i)是第⼆类斯特林数, 表示将k个元素拆分成i个集合的⽅案数。
附上斯特灵数百度百科https://baike.baidu.com/item/%E6%96%AF%E7%89%B9%E6%9E%97%E6%95%B0/4938529#4
(借图)
接下来⽤组合意义把式⼦套回原来的题⾯⾥
a
n
s
=
∑
X
∑
i
=
0
k
(
f
(
X
)
i
)
×
i
!
×
S
(
k
,
i
)
=
∑
i
=
0
k
i
!
×
S
(
k
,
i
)
∑
X
(
f
(
X
)
i
)
\begin{array}{l}{a n s=\sum_{X} \sum_{i=0}^{k}\left(\begin{array}{c}{f(X)} \\ {i}\end{array}\right) \times i ! \times S(k, i)} \\ {=\sum_{i=0}^{k} i ! \times S(k, i) \sum_{X}\left(\begin{array}{c}{f(X)} \\ {i}\end{array}\right)}\end{array}
ans=∑X∑i=0k(f(X)i)×i!×S(k,i)=∑i=0ki!×S(k,i)∑X(f(X)i)
我们在外⾯枚举了 i 之后, 要求的东⻄就是:所有⾮空点集对应的⽣成树标记了i条边的⽅案数之和
可以用树上背包求。令dp_{i,j}表示以点i为根的所有⽣成树当中标记了j条边的⽅案数, 由于点集⼤⼩之类的不影响答案,
所以不同的点集对应的⽣成树可以⼀并考虑。
对于每⼀棵⽣成树, 我们都在它最⾼的节点处累计进答案。
(借图)
时间复杂度:O(nk)
求法:
分三种情况考虑:
sz[u] >= k & sz[v] >= k,单次合并复杂度O(k^2)
此时每次相当于合并了两堆⼤⼩为⾄少为k的⽯⼦
⾄多有n/k堆, 因此合并次数为O(n/k), 总复杂度O(nk)
sz[u] >= k & sz[v] < k,单次合并复杂度O(k*sz[v])
这种情况下sz[v]之和不超过n, 因此总复杂度O(nk)。 u和v交换的情况也是如此。
sz[u] < k & sz[v] < k
相当于是正常的树上背包, 树的⼤⼩为O(k), 众所周知它的复杂度是O(k^2)
考虑每两个点之间的贡献只会产⽣于它们的lca处
最多有n/k棵这样的树, 因此总复杂度O(nk)
Uniformly Branched Trees
题目描述
如果两棵树可以通过重标号后变为完全相同, 那么它们就是同构的。
将中间节点定义为度数⼤于1的节点。
计算有n个节点, 其中所有的中间节点度数都为d的互不同构的树的数量。
答案对⼤质数取模。
数据范围
1 <= n <= 1000.
2 <= d <= 10.
108<= mod <= 109
处理同构树:
⾸先需要把⽆根树转为有根树, 不妨选取树的重心作为它的根。
性质: 任⼀⼦树⼤⼩不超过n/2。
双重⼼需要特殊考虑。
在确定根的情况下,令dp_{i,j,k}表示节点数为i, 共有j棵⼦树, 每棵⼦树的⼤⼩都不超过k的有根树数量
所有子树的大小都小于k。
d
p
i
,
j
,
k
⟵
d
p
i
,
j
,
k
−
1
d p_{i, j, k} \longleftarrow d p_{i, j, k-1}
dpi,j,k⟵dpi,j,k−1
有t棵子树的大小等于k。
d
p
i
,
j
,
k
⟵
d
p
i
−
t
×
k
,
j
−
t
,
k
−
1
×
(
d
p
k
,
d
−
1
,
k
−
1
+
t
−
1
t
)
d p_{i, j, k} \longleftarrow d p_{i-t \times k, j-t, k-1} \times\left(\begin{array}{c}{d p_{k, d-1, k-1}+t-1} \\ {t}\end{array}\right)
dpi,j,k⟵dpi−t×k,j−t,k−1×(dpk,d−1,k−1+t−1t)
不区分⼦树之间的相对顺序。
其中C_{X+t-1,t}表示在X种⽅案中不分顺序地选取t种, 可重复的⽅案数。 可以⽤组合意义理解。
d p i , j , k ⟵ d p i , j , k − 1 d p i , j , k ⟵ d p i − t × k , j − t , k − 1 × ( d p k , d − 1 , k − 1 + t − 1 ) \begin{array}{l}{d p_{i, j, k} \longleftarrow d p_{i, j, k-1}} \\ {d p_{i, j, k} \longleftarrow d p_{i-t \times k, j-t, k-1} \times\left(^{d p_{k, d-1, k-1}+t-1}\right)}\end{array} dpi,j,k⟵dpi,j,k−1dpi,j,k⟵dpi−t×k,j−t,k−1×(dpk,d−1,k−1+t−1)
统计答案:
单重⼼的情况: 答案即 d p n , d , ⌊ n 2 ⌋ d p_{n, d},\left\lfloor\frac{n}{2}\right\rfloor dpn,d,⌊2n⌋
双重⼼的情况: n为偶数, 且两个重⼼通过⼀条边相连, 各挂着⼀个⼤⼩为n/2的⼦树。
双重⼼的情形在上⼀种情况中恰好被计算了两遍, 因此减去⼀遍即可。
(
d
p
n
2
,
d
−
1
,
⌊
n
2
⌋
−
1
+
1
2
)
\left(\begin{array}{c}{d p \frac{n}{2}, d-1,\left\lfloor\frac{n}{2}\right\rfloor- 1^{+1}} \\ {2}\end{array}\right)
(dp2n,d−1,⌊2n⌋−1+12)
总时间复杂度为O(n2d2).
Multiplicity
题目描述
有个⻓度为n的序列a, 你需要统计a中有多少个棒棒的⼦序列。
⼀个序列b被定义为棒棒的, 当且仅当:
对于序列中每⼀个位置i, b_i都能够被i整除。
答案对10^9+7 取模。
数据范围
n <= 10^5
1 <= a_i <= 10^6
考虑到⼦序列中的元素相互之间是没有影响的, 令dp_{i,j}表示使⽤了a序列的前i个元素, 造了⻓度恰好为j的⼦序列的⽅案数。
转移⾮常显然:
d
p
i
,
j
=
d
p
i
−
1
,
j
+
d
p
i
−
1
,
j
−
1
×
(
a
i
%
j
=
=
0
)
d p_{i, j}=d p_{i-1, j}+d p_{i-1, j-1} \times\left(a_{i} \% j==0\right)
dpi,j=dpi−1,j+dpi−1,j−1×(ai%j==0)
维护dp_i, dp_{i+1}只需要在dp_{i}的基础上改⼏个能被a_{i+1}整除的位置。
最终的答案就是
a
n
s
=
∑
i
=
1
n
d
p
n
,
i
a n s=\sum_{i=1}^{n} d p_{n, i}
ans=i=1∑ndpn,i
时间复杂度看实现了, 最暴⼒的根号找因⼦是O(n/sqrt{A})
Maximum Element
有个神仙写了个序列求max, 它⻓下⾯这样:
现在他⽐较关⼼的是出错的情况, 请你算出有多少个1~n的排列在这个函数的计算下答案不为n。
最终结果对10^9+7取模。
枚举什么东⻄可⾏的情况都包含⼀个前提: 在此之前函数并没有退出。
那就来dp这个东⻄
在只对元素⼤⼩关系敏感的题⾥头可以将⼀段数等价地看作是相对⼤⼩不变的排列, 合并的时候注意乘上相应的组合数即可。
令 f_i 表示 1~i 的排列当中有多少个是运⾏完整个循环之后还没有退出的。
最⼤值i必然出现, 并且只可能位于[i-k+1,i]
考虑枚举最⼤值出现的位置 j
f
j
−
1
×
(
i
−
1
i
−
j
)
×
(
i
−
j
)
!
=
f
j
−
1
×
(
i
−
1
)
!
×
1
(
j
−
1
)
!
\begin{aligned} & f_{j-1} \times\left(\begin{array}{c}{i-1} \\ {i-j}\end{array}\right) \times(i-j) ! \\=& f_{j-1} \times(i-1) ! \times \frac{1}{(j-1) !} \end{aligned}
=fj−1×(i−1i−j)×(i−j)!fj−1×(i−1)!×(j−1)!1
得到
f
i
=
∑
j
=
i
−
k
+
1
i
f
j
−
1
(
j
−
1
)
!
×
(
i
−
1
)
!
=
(
i
−
1
)
!
∑
j
=
i
−
k
i
−
1
f
j
j
!
\begin{array}{l}{f_{i}=\sum_{j=i-k+1}^{i} \frac{f_{j-1}}{(j-1) !} \times(i-1) !} \\ {=(i-1) ! \sum_{j=i-k}^{i-1} \frac{f_{j}}{j !}}\end{array}
fi=∑j=i−k+1i(j−1)!fj−1×(i−1)!=(i−1)!∑j=i−ki−1j!fj
就这样计算f_i边维护⼀个前缀和
最后的答案⽤相似的⽅法枚举n所在的位置计算出最终答案为n的排列数, 再取个补集
ans = n ! − ∑ i = 1 n f i − 1 × ( n − 1 n − i ) × ( n − i ) ! \text { ans }=n !-\sum_{i=1}^{n} f_{i-1} \times\left(\begin{array}{c}{n-1} \\ {n-i}\end{array}\right) \times(n-i) ! ans =n!−i=1∑nfi−1×(n−1n−i)×(n−i)!
时间复杂度:O(n)
Easy Problem
题目描述
给出⼀个⻓度为n的字符串, 如果这个字符串中含有⼦序列“hard”, 那么这个字符串就很hard。 你不希望这个字符串很hard,所以想要从中删掉⼏个字符使他不hard。
(例: hard, hzazrzd, haaaaard 都很hard, ⽽har, hart, drah不hard)
删掉在原字符串中的第i个字符需要花费a_i的代价, 求最⼩代价
数据范围
1 <= n <= 10^5
1 <= a_i <= 998244353
Kuro and Topological Parity
题目描述
有⼀个n个点的图, 有⼀些点的颜⾊给定, 另⼀些可以随意确定。 另外, 还可以在图上连⼀些从编号较⼩的节点向编号较⼤节点的边。
对于⼀个确定的图, 统计图中节点颜⾊⿊⽩交错的路径条数, 如果奇偶性=p, 那么该图就被定义为好图。
求好图的个数, 答案对10^9+7 取模。
数据范围
1 <= n <= 50, p \in {0,1}
先考虑对于一个给定的图如何判断其是否是好图:
按照拓扑序(在本题中即为顺序) dp⼀下即可。
就计数而言,点之间只有颜色、 以其为终点的路径的奇偶性两个属性有用。
令dp_{i}{ow}{ob}{ew}{eb}分别表示dp到第i个点, 共有奇⽩、 奇⿊、 偶⽩、 偶⿊的点各ow/ob/ew/eb个时的⽅案数。 转移可以做到O(1)。 总复杂度O(n^5)。
ow+ob+ew+eb=i
有⼀维状态是多余的, 总复杂度O(n^4)。
以其为终点的路径数为偶数的点可以往后随便连。
由于我们只关注奇偶性, 同颜⾊相同的点⼀样, 往后连边时不会影响答案, 因此不需要额外记录。即计算dp_{i}{ow}{ob}即可。 总时间复杂度O(n^3)
Hero Meet Devil
题目描述
给出⼀个字符串S, 这个字符串只由’A’, ’C’, ‘G’, ‘T’四个字⺟组成。
对于每个1~|S|中的每⼀个i, 求出满⾜以下条件的字符串T的个数:
• ⻓度为m。
• 只由’A’, ‘C’, ‘G’, ‘T’四个字⺟组成。
• LCS(S,T) = i
答案对10^9+7 取模后输出。
数据范围
|S| <= 15, m <= 1000.
⾸先考虑LCS的计算过程。
当a_i = b_j时, f i , j = f i − 1 , j − 1 + 1 f_{i, j}=f_{i-1, j-1}+1 fi,j=fi−1,j−1+1
当a_i != b_j时, f i , j = max ( f i − 1 , j , f i , j − 1 ) f_{i, j}=\max \left(f_{i-1, j}, f_{i, j-1}\right) fi,j=max(fi−1,j,fi,j−1)
当i固定时,f_{i,j-1} <= f_{i,j} <= f_{i,j-1}+1
因此可以将差分序列压起来, 在本题中, 令序列a=T, 序列b=S, 那么对于⼀个确定的T的前缀, 当前的LCS状态可以⽤⼀个15位的⼆进制数来表示。
转移时枚举T新添的字⺟, 并使⽤上⾯传统的LCS计算⽅法来求出新的状态。
预处理出trans_{st}{ch}表示原来的状态为st, 新添了字⺟ch后的状态。 可以在O(|S|2^|S|)内求出。
于是
d p 0 , 0 = 1 d p_{0,0}=1 dp0,0=1
d p i , trans s t , c h + = d p i − 1 , s t d p_{i, \text {trans}_{s t, c h}}+=d p_{i-1, s t} dpi,transst,ch+=dpi−1,st
∀
c
h
∈
{
′
A
′
,
′
C
′
,
′
G
′
,
′
T
′
}
\forall c h \in\left\{^{\prime} A^{\prime}, \quad^{\prime} C^{\prime}, \quad^{\prime} G^{\prime}, \quad^{\prime} T^{\prime}\right\}
∀ch∈{′A′,′C′,′G′,′T′}
时间复杂度O(m2^|S|).
XHXJ’s LIS
题目描述
求【L,R】 中, 各位数字组成的序列的LIS恰好为k的数字个数。
数据范围
T <= 10^4.
0 < L <= R < 2^63 – 1.
1 <= k <= 10.
数位dp。
考虑二分求LIS的dp做法。
其中f_i表示⻓度为i的最⻓上升⼦序列末尾元素最⼩可以是多少。
f_i \in [0,9], 且严格上升⼦序列⻓度⾄多为10,
f_i 单调递增, 对差分序列做组合计数,
而f_i是严格单增的。
因此只需要记录0~9中每个数字在f_i中是否出现过即可。 状态数是O(2^10)的。
状态st后新添⼀个数x获得的新状态可以预处理得到。
外部就是正常的数位dp。
Make it One
题目描述
有⼀个⻓度为n的序列a, ⼀个a中的⼦集被定义为好的当且仅当它其中元素的gcd为1。
求最⼩的好的⼦集的⼤⼩。
或判断不存在这样的⼦集。
数据范围
1 <= n <= 3*10^5.
1 <= a_i <= 3*10^5.
集合具有的性质:如果有解,那么最优解的大小不超过7。
每新加⼊⼀个元素必从gcd中去除⼀个质因⼦, 否则不起作⽤可删去。
于是可以枚举答案, 然后验证是否存在⼤⼩为len, 且gcd为1的集合。
令dp_{i}表示⼤⼩为len且gcd为i的⼦集个数。
其中Cnt_i表示序列a中被i整除的元素个数, 很容易预处理得到。
当dp_1不为0时, 此时的len就合法。
由于dp值可能很⼤, 需要在模⼤质数意义下进⾏计算。
时间复杂度O(nlogn)
下午
树上数据结构
DFS可以解决的问题
路径边权和之和
求到所有点路径边权和最小f大的点
一些提高组小算法可以解决的问题(倍增、链剖、线段树、主席树)
支持修改边权和询问路径边权最大值
路径上第 k 大点/边权
给出一棵 n 个点的树,每个点有点权。 m 组询问每次问一条路径上的点权 LCIS。
链剖 + 线段树
给出一个 n 个节点的树,初始全是白点。支持翻转节点颜色和询问一条路径上第一个黑点编号。
链剖
给出两棵树,每棵树的节点都有一个权值。同一棵树上节点权值互不相同。询问第一棵树的路径 u1 -> v1与第二棵树上的路径 u2 -> v2 节点权值的交集大小。
主席树 + 链剖
树分治可以解决的问题
距离不超过 k 的路径条数
判断长度为 j 的路径是否存在
超级钢琴
堆 + ST表或堆+主席树
这是一个坑 |_|