做题记录

就是各种套路,遇到了就记录一下吧

已经快变成 DP 笔记了......

DP

转化

矩阵快速幂

看看转移的形式就可以知道了

序列玄学

求合法序列数,\(n\le 5000\)

合法序列的定义是:长为 \(n\) 且每个数为 \(\in[1,n]\) 的正整数且任意长为 \(k\) 的子序列的和严格小于任意长为 \(k+1\) 的子序列的和的单调不减序列

单调不减很好做,我们可以从一个序列 \(n,n,\cdots n\) 开始构造,因为全是 \(n\) 恰好满足所有限制,每次选择一段前缀减 \(1\)

现在只需要维护子序列和的大小随着长度增加而增加这一条件,由约束中的“任意”可知,应该选最小和最大的比较,即满足

\[\forall k\in[1,n),\;\sum_{i=1}^{k+1}a_i>\sum_{j=1}^ka_{n+1-j} \]

我们知道

\[i>j\Rightarrow a_i\ge a_j \]

所以之前的约束等价于 \(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}\) 即可,因为显然有

\[p_{k,i}i=\sum_{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)!}\)
带回上式

\[\begin{align*} p_{k,i}i&=\sum_{i=1}^n q_{k,i}\\ &=\frac{k!}{n!}\sum_{i=1}^n\frac{(n-d_i)!}{(k-d_i)!} \end{align*} \]

\(d_i\) 很难处理,所以我们枚举 \(d\)

\(c_i\)\(d_v=i\) 的点的数目,那么

\[\sum_{i=1}^n\frac{(n-d_i)!}{(k-d_i)!}=\sum_{d=1}^k\frac{c_d(n-d)!}{(k-d)!} \]

这个东西就是 \(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\)(在最后补一个空字符)

于是就有

\[ans=\sum_{i=0}^{m-1}26^i {n+m-i+1\choose n-1}25^{m-i} \]

序列

题意:给定 \(n,m\),问长为 \(2m\) 的序列满足每个数都是 \(n\) 的因数,所有数的乘积不超过 \(n^m\),问方案数

考虑配对

对于一个合法的方案,\(a_i\leftarrow\frac{n}{a_i}\) 之后,设原本的乘积为 \(\Pi\) 那么新的成绩 \(\frac {n^{2m}}{\Pi}\)

于是设 \(cnt(a)\) 表示乘积恰好为 \(a\) 的方案数

那么有

\[cnt(\le n^m)=\frac{cnt(all)+cnt(n^m)}{2} \]

转化为求 \(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\) 的大小

进行重新连边

\[\begin{align*} s_i\in son_u\\ s_i\rightarrow v_i\\ v_{i+1}\rightarrow v_i\\ v_1\rightarrow u \end{align*} \]

也就是搞成一条链的形式,然后把原本的儿子挂到链上,也可以写成线段树一样的递归写法,有时候常数会小一点,不过挺难打的

树上启发式合并

放到分治里面是因为 \(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)\)

\[f(l,r)=\left\{\begin{align*}r-l+1\qquad&t(l,r)=0\\\operatorname{max}\{f(l,t(l,r)-1),f(t(l,r)+1,r)\}\qquad& t(l,r)\ne 0\end{align*}\right. \]

然后就是启发式合并的套路了,我们开一个桶记录每个数的出现次数,假设合法,直接暴力删除

不合法的话会变为两个子问题,记为 \(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)\)

posted @ 2022-06-25 16:35  嘉年华_efX  阅读(68)  评论(0)    收藏  举报