学习一波鸽子的更博方式
Codeforces 623E:Transforming Sequence
(f_{i,j}) 表示前 (i) 个,选了 (j) 个二进制位
(f_{i,j}=sum f_{i-1,k}2^kinom{j}{k})
倍增+(MTT) 即可
Codeforces 553E:Kyoya and Train
(f_{i,j}) 表示 (i) 到 (n) ,时间为 (j) 的最小期望代价
对于时间分治 (+FFT) 即可
复杂度 (O(mTlog^2T))
Codeforces 923E:Perpetual Subtraction
首先显然有一个 (dp),(f[i][j]) 表示前 (i) 轮之后为 (j) 的概率
那么 (f[i][j]=sum_{kge j}frac{f[i-1][k]}{k+1})
不会线性代数,不会矩阵
设生成函数 (F_i(x)=sum_{j} f[i][j]x^j)
那么
设 (G_i(x)=F_i(x+1))
那么
展开就是
那么也就是 (g[i+1][j]=frac{g[i][j]}{j+1}) 即 (g[m][j]=frac{g[0][j]}{(j+1)^m})
现在考虑 (f) 和 (g) 的关系
也就是
那么二项式反演之后就是
这两个东西都可以拆开之后 (NTT)
LOJ161:仙人掌计数
求 (n) 个节点无重边、自环,有标号的仙人掌个数
设 (C(x)) 为其指数级生成函数
可以考虑把它分成若干个部分,然后 (exp) 起来
那么可以钦定一个点删掉,也就是弄个根
设 (F(x)) 为有根仙人掌个数的生成函数
显然有 (F_i=iC_i)
考虑删掉根之后的图长成什么样子
对于与根不在一个环上的相邻节点,就会变成以该点为根的仙人掌,生成函数为 (F(x))
对于与根在一个环上的相邻节点,把这个环拆开,变成以环上的点为根的仙人掌,由于还可以翻转,那么生成函数为 (sum_{ige 2}frac{F^i(x)}{2})
把这些东西 (exp) 起来,即
加上删去掉的根,即
对这个东西牛顿迭代求解 (F(x)) 即可
注意由于 (F_0=0),没有办法对它求 (ln)
CTT2017:生成树计数
推导:
根据 (prufer) 序列,答案显然就是
后面那个 (sum_{i=1}^{n}(d_i+1)^m) 可以看成是做 (n) 次求和,每次钦定一个连通块的贡献为多乘上一个 ((d_i+1)^m)
考虑生成函数
设 (F(x)=sum_{i}frac{(i+1)^m}{i!}x^i,G(x)=sum_{i}frac{(i+1)^{2m}}{i!}x^i)
那么答案变成
先考虑计算 (prod_{i=1}^{n}F(a_ix))
(复合函数的结合律)
那么只要求 (sum_{i=1}^{n}(lnF)(a_ix))
而又要求 (sum_{i=1}^{n}frac{G(a_ix)}{F(a_ix)}=sum_{i=1}^{n}(frac{G}{F})(a_ix))
也就是考虑这样一个问题
已知 (f_i,a_i) 求 (sum_{i=1}^{n}sum_{j}f_ja_i^jx^j) 的每一项系数
也就是要求 (forall j,sum_{i=1}^{n}a_i^j),然后对应位置相乘
即要求 (sum_{i=1}^{n}frac{1}{1-a_ix}) 的每一项系数
下面的可以分治 (FFT),上面的也可以分治计算,(O(nlog^2n))
所以此题复杂度 (O(nlogn+nlog^2n+nlogm)) 其中 (nlogm) 为快速幂
UOJ462:新年的小黄鸭
设 (f_u) 表示选完了 (u) 的子树的答案
枚举 ((u,v)) 一条重链,转移贡献为 (sum_{xin (u,v)} (lceil log_2dis(x,u)
ceil +1)+sum_{xin subtree_u,x
otin (u,v)}f_v+size_v)
后面的 (sum) 很好维护,主要是前面的
直接把贡献拆分成 (log) 个,分 (log) 次加入,用一个 (nlog_2n) 的数组把每个点挂在它的 (2^i) 的祖先上
只需要在一棵线段树修改+查询即可
LOJ2773:「ROI 2017 Day 2」学习轨迹
首先如果只在一个学校上课的话,答案显然就是选择所有的课程。
否则在两个学校上课,不难证明至少有一所学校上课的权值和必定大于其所有权值和的一半 (否则不如在某一个学校上课)。
对于权值做前缀和,假设 (THU) 的前缀和是 (S_a) ,(PKU) 的前缀和是 (S_b), 不难证明只要超过了一半,必定会选择前缀和第一次 (frac{1}{2}S_a) 和 (frac{1}{2}S_b) 的位置。
不妨先随便令一所学校要跨过中位数。比如说 (THU) 吧。
那么显然答案就是在 (PKU) 的课程中随意选择一段,然后把重复的课程在 (THU) 的课表中标记出来,然后从中位数开始向两侧拓展,能走就走。
那么设 (f[l][r]) 表示选择了 (PKU) 的 ([l, r]) 这一段的答案,那么枚举右端点用线段树动态来维护这个东西。
贡献显然是 (S_b[r] − S_b[l − 1] + S_a[R] − S_a[L − 1])。
因为是从 (mid) 位置开始,向左右两侧拓展。
那么我们枚举右端点之后,两侧分别维护一个单调队列。
首先因为枚举了 (r),所以 (S_b[r] − S_b[l − 1]) 很容易计算,现在问题就在于如何维护 (S_a[L, R])。
在单调队列加入当前位置和弹掉当前位置的时候,会影响一段区间的贡献,在线段树上修改即可。
BZOJ5014:[IOI2017]Wiring
模拟费用流
拆点,一个权值为 (-infty),容量为 (1),另一个权值为 (0),容量为 (infty)
因为两侧都有了容量为 (infty) 的点,所以我们要重新分析一下复杂度。
如果是第一类点 (a) 匹配了左边某一个点 (b) ,则 (b) 不可能反悔。因为 (a) 是必须匹配的, (b) 一旦反悔,a 和 (b) 将同时连往 (a) 右边的点,匹配交叉,矛盾
如果是第二类点 (a) 匹配了左边某一个点 (b) ,则 (b) 一定是第一类点。因为 (b) 是必须匹配的,所以 a 一旦反悔, (a) 和 (b) 将同时连往 (a) 右边的点,匹配交叉,矛盾
所以,每次匹配完之后,只有一方可能反悔。增广总次数不超过 (2n)
看代码清晰的多QwQ
if (!hole.empty()) {
ans += (v = -hole.top().first + x[i]);
id = hole.top().second, mouse.push(make_pair(x[i] + v, 0));
hole.pop();
if (id) hole.push(make_pair(y[id], id));
while (!hole.empty() && -hole.top().first + x[i] < 0) {
ans += (v = -hole.top().first + x[i]);
id = hole.top().second, hole.pop();
hole.push(make_pair(x[i], 0));
if (id) hole.push(make_pair(y[id], id));
}
}
else ans += inf, mouse.push(make_pair(x[i] + inf, i));
mouse.push(make_pair(x[i], i));
UOJ455:雪灾与外卖
遇到一只老鼠时,老鼠可能会先匹配之前的堆,然后往老鼠堆中丢一个这只老鼠反悔的操作。
这个过程放到本题,堆操作总次数依然是线性。
当遇到一个洞时,洞可能会匹配一大堆老鼠,即从老鼠堆中取一大堆元素。然后洞和老鼠都有可能反悔,这样要同时往老鼠堆和洞堆中丢元素。
每次一个洞匹配了若干个老鼠之后,往老鼠堆中丢的元素都是等权的。这样我们就只需要在堆中对每个元素记录一下出现的次数,堆的操作总次数就变成了线性。
LOJ6405:「ICPC World Finals 2018」征服世界
在 (lca) 处考虑,模拟费用流,维护两个可并堆即可
BZOJ3724:PA2014Final Krolestwo
对于二分图,从 (X) 交替走回到 (X) 部的路径长度一定是偶数。
沿用欧拉路做法,建一个点 (Root),把 (Root) 与度数为奇的点连边。
然后考虑把点 (u) 拆成两个点 (u、u') ,把原图改造成二分图。
改造后:
原图边 ((u, v)) 对应 ((u, v′)) 或者 ((v, u′)) 中的一条。
每个点的度数为偶数。
如果能做到上述转化,跑欧拉路即可得解。
因为每个点度数为偶,即不存在脱离的边,所以一定能跑出解。
转化方法?
首先先一顿乱连,把二分图整出来。
显然若保证左侧度数都为偶数,那么右侧一定度数都为偶数。
然后跑原图的一棵生成树,自底向上不断调整即可。
Codeforces GYM 101955 F:Counting Sheep in Ami Dongsuo
设 (f_{u,i,j}) 表示 (u) 号点,选了 (j) 个终点,权值和为 (i) 的方案数
建反图跑一边即可预处理
最后对于每一个 (i),(f_{u,i,3}) 加起来就是答案
直接做是 (O(81mw^2)) 的,代入 (w+1) 个点求点值,最后插值即可
复杂度 (O(27mw+9w^2))
Luogu T68477:珍珠游戏
很好的一道题目
首先第一个想法就是设 (f_i) 表示 (w_i) 贡献的期望次数
那么 (ans=sum f_iw_i)
怎么求 (f_i)
这个题目就妙在这里,把包含 (i) 的块拆成前面和后面(美妙的期望的线性性)
设 (g_i) 表示一个长度为 (i) 的块,它的首部贡献的期望次数
那么 (f_i=g_i+g_{N-i+1}-1),多算了所以要 (-1)
(g_i) 很好算,(g_i=sum_{jle i} frac{1}{j}),即每个位置在前所有位置之前取走的概率
Codeforces 1097E:Egor and an RPG game
可以发现 (f(n) = k − 1),其中 (k = min){(x|frac{x(x+1)}{2}> n)}。
考虑证明同时构造答案。
对于长度为 (n) 的序列,设其 (LIS) 长度为 (len)。
若 (len le K), 则 (n − len < frac{K(K+1)}{2}-K=frac{K(K-1)}{2})
若 (len < K), 根据 (Dilworth) 定理,可以用 (< K) 个下降序列覆盖, 只需要把以 (i) 相同的长度的点分成一组即可
ps:Dilworth:(DAG) 中的最小链覆盖数等于其最长反链
在这里就是最长上升序列长度等于最少下降序列的覆盖
UOJ461:新年的Dog划分
先构出一棵生成树,判断是否是二分图只要在这个生成树中看一下有没有同奇偶性深度的边(奇环)即可
怎么构造一棵生成树?
考虑从一个点开始每次找出一条与它相连的边
一个比较好的方法就是 (BFS),把已经在生成树里面的不在队列中的点到任意点的非树边全部去掉
当没有加入的点有若干个只与当前点连通时扩展,这样的点的存在性可以判断,找到这样的点可以二分
UOJ454:【UER #8】打雪仗
通信题
对于 (task1) 直接 (Alice) 返回所有,(O(2n))
对于 (task2) 可以分成两部分,询问多一半直接 (Alice) 返回,少的 (Bob) 询问,(O(n+frac{n}{2}))
对于 (task3) 可以分成三部分,询问多的 (frac{1}{3}) 直接 (Alice) 返回,少的 (Bob) 询问,(O(n+frac{n}{3}))
Codeforces 750F:New Year and Finding Roots
首先如果一开始就找到了一个叶子,那么暴力去递归找它的父亲,每次随机一个方向(除了已知的儿子)走深度次,如果走到了一个叶子就不是这个方向
(设根的深度为 (1))这样子最后到达深度为 (3) 的点需要花费 (11) 次
注意到此时只有与该点距离不超过 (2) 的点可能是根,这样的没有询问过的点不超过 (6) 个
所以只要询问 (5) 次,一共 (16) 次
如果一开始不是叶子,那么尝试 (dfs) 到一个叶子,最后再套用上面的做法
注意每次随机一个方向的时候要判断之前是否已经有一条长度为深度的链(也可以优先选择询问过的点)
Codeforces GYM 101741H:Compressed Spanning Subtrees(H)
首先可以 (O(n)) 找出所有的叶子
为了保证得到祖先关系,选择某个叶子为根
这样可以求出每个叶子的所有祖先
将它的祖先按照 (size) 排好序,一个个接上去就可以得到这棵树了(因为不存在度数为 (2) 的点)
询问次数 (O(frac{n^2}{4}))
Hackerrank:Build a Palindrome
枚举长的那个的回文串即可。(PAM+SAM+hash) 乱搞。
BZOJ4061:[Cerc2012]Farm and factory
设新加入的点为 (x),(d) 为新的距离,(a,b) 分别为原图中到 (1,2) 的距离,那么就有一些限制
(d_{x,i}+d_{x,1}ge a_i)
(d_{x,i}+d_{x,2}ge b_i)
而根据最短路,又有一些限制
(d_{x,1}le d_{x,i}+a_i)
(d_{x,2}le d_{x,i}+b_i)
可以得到
(d_{x,i}ge max(|d_{x,1}-a_i|,|d_{x,2}-b_i|))
显然是可以达到 (max(|d_{x,1}-a_i|,|d_{x,2}-b_i|)) 的
现在的问题在于怎么确定 (d_{x,1},d_{x,2}) 的值
不难发现上面的 (max) 就是一个切比雪夫距离的形式,直接弄成曼哈顿距离即可。
分别取出中位数就是答案。
Luogu U28854:pfs
(min25) 第二部分的时候强行计一个最大的指数即可。
Atcoder ARC101 C:Ribbons on Tree
容斥+树形 (DP),转移加个容斥系数就没了。
LOJ6494:LJJ 的字符串
枚举两个前缀的距离计算,差分一个二次函数即可,类似 [NOI2016]优秀的拆分。
Codeforces 1131G:Most Dangerous Shark
预处理出每个点向右和向左能扩展到哪里,(l_i,r_i)。
一个性质就是扩展的区间要么包含,要么相离。
(f_i=min(f_{j-1}+c_j(j < i le r_j),f_{l_i-1}+c_i))
单调栈处理 (l,r,f) 即可。
HDU5279:YJC plays Minecraft
设 (f_i,g_i) 分别表示 (i) 个点的树和森林的个数,(F,G) 为其指数生成函数,显然 (G(x)=e^{F(x)})。
为了计算答案,再设 (h_i) 表示 (i) 个点,(1,n) 在同一个连通块的方案数。
那么 (h_{i}=sum_{j=0}^{i-2}g_jf_{i-j}inom{i-2}{j}),显然可以写成卷积的形式。
最后 (ans=2^nprod_{i=1}^{n}g_{a_i}-prod_{i=1}^{n}h_{a_i})
以上用多项式各种运算即可实现。
LOJ6146:「2017 山东三轮集训 Day7」Normal
强行循环卷积+单位根反演海星
BZOJ4241:历史研究
回滚莫队
BZOJ5473:仙人掌
首先,所有连通块的个数的期望再减去每个点孤立的概率就是答案。
设 (d_i) 表示 (i) 的度数,那么每个点孤立的概率为 (frac{1}{2^{d_i}})
考虑计算所有连通块的个数的期望
对于一棵树来说,每次删除一条边会使得连通块的个数 (+1),概率为 (frac{1}{2}),那么 (n-1) 条边的期望就是 (1+frac{n-1}{2})
对于仙人掌来说,如果这次删的是环上第一个被删除的边,那么不会贡献答案,所以要减去在一个环上至少删除了一条边的概率,设长度为 (len),就要减去 (1-frac{1}{2^{len}})
所以只要求出每个环就好了。
【清华集训2016】数据交互
对于一棵有根树上的两条链 ((x_1,y_1)) 与 ((x_2,y_2)),若两条链存在交点,必然有:(lca_{x_1,y_1}) 在链 ((x_2,y_2)) 上,或者 (lca_{x_2,y_2}) 在链 ((x_1,y_1)) 上。
对于链 ((u,v)),答案为所求 (lca) 在 ((x,y)) 的链的权值的和+过点 (lca_{x,y}) 的且 (lca
e lca_{x,y}) 的链的权值和。
每个点维护一个答案,维护一个类似于区间最大子段和的东西,维护一个最长链,维护所有轻边儿子的最长链的 (priority\_queue) 然后上线段树+树链剖分即可。
[HEOI2013]SAO/[CQOI2017]老C的键盘
给定一个树形图,求合法拓扑序的个数。
设 (f_{u,i}) 表示点 (u),有 (i) 个在其前面的方案数。
当 (u > v) 时,则 (f_{i,i+j}=f_{u,i} imes (sum_{k=0}^{j-1}f_{v,k}) imes inom{i+j}{i} imes inom{size_u(now)+size_{v}-j-i-1}{size_{v}-j})
当 (u < v) 时,类似。
前缀和优化即可。
[CTSC2018]青蕈领主
一些性质:(L_n=n);区间相离或包含;区间内数字连续。
这些区间的包含关系形成了树形结构。
设 (i) 有 (cnt_i) 个儿子,那么答案就是 (prod_{i=1}^{n}f_{cnt_i})
其中 (f_n) 表示长度为 (n+1) 的排列,除了最后一个位置的 (L=n+1) 以外,其它的都为 (1)。
考虑计算 (f_{n}),设 (a_{p_i}=i),相当于是所有连续区间必须包含最大值。
考虑加入最小值:
首先本来就合法,(f_{n-1}(n-1))
其次,枚举不合法的长度 (iin [2,n-2]),相当于中间的这一段的连续区间都必须经过最小值,而区间最小值可以取 ([2,n-i])
那么就是 (sum_{i=2}^{n-2}f_{i}f_{n-i}(n-i-1))
这个玩意儿是可以 (CDQ) 分治 + (FFT) 的,怎么做呢?
分治的时候用 ([l,mid]) 卷上 ([1,r−l]),然后加到 ([mid+1,r]) 上,但问题是 (r−l) 之类的可能还没求出来。
差不多是一个拆开贡献计算的思路。
这次可以首先算出 ([l,mid]) 卷上 ([1,mid(r-l,mid)]) 的贡献,由于之前在算 ([1,min(r-l,l-1)]) 的时候没有算 ([l,mid]) 的,所以再次算一遍 ([l,mid]) 和 ([1,min(r-l,l-1)]) 把贡献补回来。