做题记录
就是各种套路,遇到了就记录一下吧
已经快变成 DP 笔记了......
DP
转化
矩阵快速幂
看看转移的形式就可以知道了
序列玄学
求合法序列数,\(n\le 5000\)
合法序列的定义是:长为 \(n\) 且每个数为 \(\in[1,n]\) 的正整数且任意长为 \(k\) 的子序列的和严格小于任意长为 \(k+1\) 的子序列的和的单调不减序列
单调不减很好做,我们可以从一个序列 \(n,n,\cdots n\) 开始构造,因为全是 \(n\) 恰好满足所有限制,每次选择一段前缀减 \(1\)
现在只需要维护子序列和的大小随着长度增加而增加这一条件,由约束中的“任意”可知,应该选最小和最大的比较,即满足
我们知道
所以之前的约束等价于 \(k=\lfloor\frac n2\rfloor\) 的情形
我们维护差分 \(d=\sum\limits_{i=1}^{k+1}a_i-\sum\limits_{j=1}^ka_{n+1-j}\)
暴力处理出每个前缀减 \(1\) 对 \(d\) 的影响,\(d>0\) 就合法,然后就转化为了完全背包(因为每次至少使 \(d\leftarrow d-1\),所以值域的约束不用考虑)
二分答案套DP
树的直径
题意:树有点权和边权,点权 \(w_u\) 可以使得 \(u\in e,e\leftarrow \operatorname{max}(e-w_u,0)\),每个点权只能用一次,求最小直径
直接做不太可做,可以先二分答案,用 \(DP\) 检验,考虑点权给到子树内还是子树外,分类讨论一下就可以了
HDU7163
有一个血量为 \(H\) 的 boss,你有 \(n\) 个技能,每个技能 \(i\) 释放后可 以在接下来的 \(l_i\) 秒中第 \(j\) 秒造成 \(d_{i,j}\) 点伤害,释放后需要冷却 \(t_i\) 后才能释放另外的技能(不是持续的伤害结束后),每个技能只能释放一次,问最少需要消灭 boss 需要的时间
这题 \(n\) 很小,可以直接退火,不过检验需要优化,发现可以二分最后的时间,然后就过了
\(DP\) 的话,考虑二分时间,用 \(DP\) 检验可行性,最后直接做就可以了
钦定状态
ARC150 D
给一棵树,一开始所有点都是白色的,每次把一个点染成黑色,如果一个点到根路径上所有点(包括起点和终点)都是黑色的,这个点就是好的,否则就是坏的。每次随机选一个坏点染黑(即使它已经是黑色的),直到没有白点,问期望染色次数
设从 \(k\) 给黑点到 \(k+1\) 个黑点需要操作 \(X_k\) 次,那么答案就是 \(\sum_0^{n-1}X_i\)
假设有 \(m\) 个好点,\(k\) 个黑点的概率是 \(p_{k,m}\),之后每次操作可以选 \(n-m\) 个点,选出新黑点的期望时间是 \(\dfrac{n-m}{n-k}\)
选出新黑点的期望时间显然就是在有 \(m\) 个好点,\(k\) 个黑点的状态下变成新状态的期望时间,也就是 \(p_{k,m}\rightarrow p_{k+1,m^\prime}\) 的期望时间(\(m^\prime-m\) 的值是我们不知道的,因为可能一下多出很多好点)
不难推出 \(X_k=\sum\limits_{i=0}^kp_{k,i}\dfrac{n-i}{n-k}=\dfrac{n}{n-k}-\sum\limits_{i=0}^kp_{k,i}i\)
现在,只需要求出 \(\sum\limits_{i=0}^kp_{k,i}i\),这个东西的组合意义显然是期望的好点个数
可以设 \(q_{k,i}\) 表示节点 \(i\) 在有 \(k\) 个黑点时是好点的概率,因为染色是随机的,所以最后黑色节点的分布也是随机的(黑坏点只会影响到达状态的期望时间,不会影响状态的分布概率)
那么只需要对所有的 \(k\) 求出 \(\sum\limits_{i=1}^n q_{k,i}\) 即可,因为显然有
设 \(d_i\) 为 \(i\) 到根路径上的节点数,因为黑点分布是随机的,所以一共 \(\binom{n}{k}\) 种染法被选中的概率是一致的
要 \(i\) 是好点,那么需要从 \(i\) 到根路径上的 \(d_i\) 个点都是黑点,这个概率是 \(\binom{n-d_i}{k-d_i}\)
于是 \(q_{k,i}=\dfrac{\binom{n-d_i}{k-d_i}}{\binom{n}{k}}=\dfrac{k!(n-d_i)!}{n!(k-d_i)!}\)
带回上式
\(d_i\) 很难处理,所以我们枚举 \(d\)
记 \(c_i\) 为 \(d_v=i\) 的点的数目,那么
这个东西就是 \(c_d(n-d)!\) 和 \(\dfrac{1}{d!}\) 的卷积,记得出的数列为 \(P\)
那么 \(p_{k,i}i=\dfrac{k!}{n!}P_k\),然后前缀和一下就可以推出 \(X_k\)
于是 \(O(n\log n)\) 做完了
附带一个神仙做法
考虑 \(X_k\) 是点 \(k\) 被染色的次数,那么我们只需要考虑 \(k\) 到根路径上的点(别的点会被别的点统计)
然后用 \(f_{i}\) 表示有 \(i\) 个好点的情况,发现只能 \(f_i+\dfrac{1}{k-i}\rightarrow f_{i+1}\),而每一次转移时 \(k\) 被选中的概率也是 \(\dfrac{1}{k-i}\),于是 \(X_k=H_k=\sum\limits_{i=1}^k\dfrac1i\)
最后答案显然是 \(\sum X_i\)
组合计数
这一块和后面容斥计数有重合
饼干
题意:\(k\) 天,每天随机给 \(n\) 个人中的 \(a_i\) 个一人一块饼干,最后记一个人的饼干数为 \(c_i\),问 \(\prod c_i\) 的总和
直接做不好做,考虑转化,假设每个人都有一块特殊的饼干,而其他的饼干都是普通的,那么最后每个人都拿到了特殊饼干的方案数就是 \(\prod c_i\) 的总和(考虑组合意义)
字符串变换
题意:往一个字符串里任意位置插 \(m\) 个任意字符,问得到的本质不同的字符串数
钦定原串在最后的串中出现在最后
枚举在原串前的字母数,发现钦定的约束等价于 \(c_i\) 和 \(c_{i+1}\) 之间不能放 \(c_i\)(在最后补一个空字符)
于是就有
序列
题意:给定 \(n,m\),问长为 \(2m\) 的序列满足每个数都是 \(n\) 的因数,所有数的乘积不超过 \(n^m\),问方案数
考虑配对
对于一个合法的方案,\(a_i\leftarrow\frac{n}{a_i}\) 之后,设原本的乘积为 \(\Pi\) 那么新的成绩 \(\frac {n^{2m}}{\Pi}\)
于是设 \(cnt(a)\) 表示乘积恰好为 \(a\) 的方案数
那么有
转化为求 \(cnt(n^m)\),容易求解
容斥计数
硬币购物
题意:有四种钱 \(c_i\),有数量限制 \(d_i\),问凑 \(s\) 元的方案数
没有约束就是完全背包,有约束的话就减去已经拿了 \(d_i+1\) 的方案数,然后发现会多减,需要容斥
卡农
题意:求值域为 \([1,n]\),大小为 \(m\) 的集合数,满足要求
1.合法集合中的元素是 \([1,n]\) 中部分数构成的非空集合
2.合法集合中 \([1,n]\) 每个数出现偶数次
考虑 \(dp\),设 \(f_i\) 表示到第 \(i\) 个集合的方案数
因为每个数在集合中要出现偶数次,在一个子集中只能出现 \(1\) 次,所以前 \(i-1\) 个确定的条件下,第 \(i\) 个集合也是确定的,不考虑约束,有 \(A_{2^n-1}^{i-1}\) 种方案
因为不能为空集,那么前 \(i-1\) 个不能构成合法的方案,即有 \(f_{i-1}\) 种不合法方案
再考虑两个子集相等,注意到两个相等的子集合起来一定合法,所以要除去 \(f_{i-2}\) 种方案,然后枚举相等的子集的编号有 \(i-1\) 种,相等子集的取值有 \(2^n-i+1\) 种
这道题也可以用来练FWT
枚举子集
inline void GospersHack(int n, int k)
{
int cur = (1 << k) - 1;
int limit = (1 << n);
while (cur < limit)
{
work(cur);
int lb = cur & -cur;
int r = cur + lb;
cur = ((r ^ cur) >> (__builtin_ctz(lb) + 2)) | r;
}
}
可以枚举 \(n\) 个元素中选 \(k\) 个的方案数,复杂度就是 \(O({n\choose k})\),因为用的是位运算,常数几乎没有
求有个数约束的子集都可以,求所有子集更不在话下
ds
分治
关于直径点集合并
一个 \(cluster\) 的直径是 \(path(u,v)\) 那么两个 \(cluster\) 合并时得出的 \(cluster\) 的直径的端点只能是 \(u_1,v_1,u_2,v_2\)
静态树的三度化
在各种树分治中都还是很常见的,就讲一讲,
一个点 \(u\) 的儿子集合为 \(son_u\)
我们构造若干个虚节点 \(v_1\cdots v_n\),其中 \(n\) 为 \(son_u\) 的大小
进行重新连边
也就是搞成一条链的形式,然后把原本的儿子挂到链上,也可以写成线段树一样的递归写法,有时候常数会小一点,不过挺难打的
树上启发式合并
放到分治里面是因为 \(dsu\ on\ tree\) 能够解决的问题和分治类似,并且分析也是差不多
举例
一个大小为 \(n\) 的有根树的点有颜色,求每个子树内有多少不同的颜色,\(O(n)=10^6\)
最暴力的做法是用桶维护答案, \(O(1)\) 求出叶子答案,然后从叶子一路合并到根就做完了,但这样是 \(O(n^2)\) 的
因为只需要答案,所以可以选择直接继承重儿子的桶用来存答案,然后发现一个点的合并次数等于其到根路径上的轻边数,于是就是 \(O(n\log n)\) 了
区间分治
我也不知道这个到底叫什么
求最大的合法区间,合法的定义是 \(i\) 出现的次数 \(\in[l_i,r_i]\),\(n\le 10^6\)
考虑分治,定义 \(f(l,r)\) 为区间 \([l,r]\) 的答案
考虑到一个区间如果不合法,至少有一个位置的值不合法,记任意一个这样的位置为 \(t(l,r)\)
然后就是启发式合并的套路了,我们开一个桶记录每个数的出现次数,假设合法,直接暴力删除
不合法的话会变为两个子问题,记为 \(A,B\),不妨让 \(|A|\le|B|\),然后暴力删 \(A\),解决 \(B\),再递归到 \(A\),这样只会有 \(O(\log n)\) 层,每层复杂度为 \(O(n)\),最后总复杂度就是 \(O(n\log n)\)
定义非空可重集 \(A<B\) 当且仅当,\(A\) 中最小元素在 \(A\) 中出现次数多于 \(B\)
求一个序列的所有区间构成的可重集中的第 \(k\) 大,\(n,a_i\le 10^6\),数据随机
我们用四元组 \((a,b,c,d)\) 表示 \(l\in [a,b],r\in [c,d]\) 的若干个区间,所有区间可以表示为 \((1,n,1,n)\)
我们枚举 \(x:1\rightarrow n\),考虑 \(x\) 在最后答案中的个数为 \(c_x\),记符合情况的区间数为 \(m_c\),那么应该有 \(m_c\ge k\and m_{c-1}<k\)
暴力即可,直至只余下一个区间,在随机数据下表现优秀,但我不会证复杂度,不过上界大概是 \(O(n\sqrt n\log n)\)
线段树hash
有时候,我们需要对于一个区间信息进行某种合并,如果是完全相等的区间则不需要合并,一般就可以使用线段树维护区间hash的做法,如果不匹配就暴力往下跳,往往是均摊 \(O(\log^2 n)\) 的

浙公网安备 33010602011771号