nfls集训有意思的题
其实只是为了记录懒得写总结的答辩场中一些有趣的题
Day3D1T2
考场上没想到转化成期望,转成期望以后就非常简单了。
首先把贡献均摊的每一条边,计算边两侧点的期望数量。
一条边操作过后两侧点的数量不会再变化,所以我们只考虑操作这条边之前两端点的数量。
先考虑正常情况下交换一条边的情况,设边 \((x,y)\),\(x\) 那侧一共有 \(S_x\) 个点,\(x\) 上有 \(a_x\) 个点,同理对 \(y\) 定义。
原来这条边产生的贡献是 \(S_xS_y\),如果把 \(x\) 给到 \(y\),那么贡献变成了 \((S_x-a_x)*(S_y+a_x)\),拆开是 \(S_xS_y+(S_x-S_y)a_x-a^2_x\),对 \(y\) 类似。
发现式子中有平方项,于是我们需要对每个点维护两个值,\(f_x\) 表示 \(x\) 的期望点数,\(g_x\) 表示 \(x\) 的点数的平方的期望(注意不等于期望的平方)。
那么维护就非常简单了,直接让 \(f'_x=f'_y=\frac{f_x+f_y}{2}\),\(g'_x=g'_y=\frac{g_x+g_y+2f_xf_y}{2}\) 即可。
答案的话就在计算这条边的影响之前用 \(f_x,f_y,g_x,g_y\) 计算一下即可。
复杂度线性。
Day5D1T2
挺有意思的网络流题。
看到这个东西就很像志愿者招募,但是并不完全是。
先把前缀和转换成差分的形式,其中第0项和第 \(n\) 项设成 inf 就好,然后每次操作看做给长度为 \(l+1\) 的区间开头 +/- 1,结尾相反操作,我们希望用最小的费用使得每个数字非负。
转换到图上,我们假如把流入1流量看做给这个点+1,流出1流量看做给这个点-1,那么我们希望所有点的 \(流入量+点权-流出量\geq 0\),移项就变成了 \(流出量\leq 流入量+点权\) 。
于是我们给每个点向源点连 \(inf\),向汇点连 \(inf+点权\),就解决了流量的问题,如果满流的话就说明有解。
那么 + 操作就可以看做把一个点的多余不要的流入量分摊一些到其他的点作为它的流出量来达到满流的目的,同样的分摊1流量的代价就是1次操作的费用,- 操作是类似的。
建出来图跑最小费用最大流即可,复杂度 \(O(能过)\)。
Day8D1T2
有点东西的DS,但东西不多。
看到维护的是矩阵就非常震撼,而且查询的是每一列的和的最小值,看上去非常难维护。
如果没有2操作是非常简单的,关键就在于2操作区间覆盖怎么处理。
考虑行数很小,直接状压行,线段树维护的点值是只考虑状态里的行这一列的和。
那么对于区间覆盖操作,只含有这一行的线段树直接打区间覆盖标记,其他的含有这一行的线段树可以通过把去掉这一行的状态的线段树这个区间这段嫁接到他上面再打一个加法标记。
需要用到一些可持久化下传标记的技巧,还是挺好写的。
复杂度 \(O(n2^mlogn)\),空间复杂度 \(O(?)\),开了5个7e7的数组居然没爆内存。
Day8D1T3
机房很多人说这是杨表一眼题,wtcl
考虑对每个合法排列处理出来每个点为结尾的 lis 和 lds,发现这些二元组一定两两不同,证明考虑如果存在一对相同的,那么因为是排列,其中一个肯定能从另一个+1转移而来,这与两个二元组相等矛盾。
接着考虑构造矩阵 A,B,满足 \(A_{lis_i,lds_i}=i,B_{lis_i,lds_i}=p_i\),发现 A 每行每列均递增,B 每行递减,每列递增。
证明:

接下来证明每个矩阵对都唯一定义一个合法排列:

(这个东西好像就叫杨表)
那么考虑计数这样的矩阵对,我们希望得到 \(A_{x,y}=i,B_{x,y}=j\) 的方案数。
考虑从 \(1\) 到 \(nm\) 去填数,那么形成的形状类似一个阶梯型,枚举所有的阶梯型DP,总数量上界大概是 \(4e5\)。
具体的,可以算出来填了前 \(i\) 个数第 \(i\) 个数放在位置 \(j,k\) ,阶梯型的形状是 \(s\) 的方案数,枚举那么可以通过正反拼起来的方法得到所求。
\(A\) 和 \(B\) 独立且左右对称,所以做一遍 \(DP\),就好。
复杂度 \(O((nm)^3+nm * 状态数 * hash)\)。
Day10D1T4
看上去邻域查询异或可能需要top tree科技,但实际上只需要倍增。
这题的邻域只有子树内,让我们把问题想简单一点。
考虑邻域在 bfs 序上是连续的,所以考虑维护 bfs 序,也就是按深度分类分成若干层。
没有修改,所以只需要考虑预处理和查询,查询可以简单在 bfs 序上做差分,具体的,从根出发一直向最右边走查询的层数,特别的,对于子树内某层的末尾,我们强行
把他拉倒下一层应该在这个点之前的那个点,如图:

那么现在就只有预处理了,考虑倍增,好处不仅在意可以 \(log\) 维护信息,而且能巧妙地与异或这种二进制操作结合。
口嗨很简单,写起来还是有细节。
总之复杂度 \(O(nlogn)\),代码也不算难写。
Day14D1T2
代码短的妙妙字符串题。
不难想到把所有 \(D\) 中的串插入trie中,那么查询的时候就相当于把 \(s\) 拿到 trie 上跑一遍,对于一个 \(s\) 经过的节点会对答案产生所有字符边小于当前边的兄弟的子树和的贡献(子树和维护子树内有多少个 \(D\) 中的串的终止位置),如果不是 \(s\) 的结尾那么到当前位置结束的 \(D\) 中的串也是需要加入答案的。
直接模拟复杂度是平方级别,考虑优化,下文设把第 \(k\) 位之后改成 \(c\)。
考虑每次修改是改变一段后缀,那么考虑在trie上预处理出从每个点只沿某同一种字符边走到最后是哪个节点,注意深度是不能大于 \(|s|\) 的,这不难做到 \(O(n|\sum|)\),然后考虑算答案时每个点字符边小于他的兄弟子树和,这个也不难 \(O(n\sum)\) 预处理出来。
第一次询问随便搞,我们假设把 \(s\) 一直在trie上匹配到最后一个能匹配的位置,设为 \(mat\)。
算答案借用上面预处理的东西不难计算。
首先如果 \(k>mat+1\) ,那么这次操作无效,跳过即可。
否则就需要解决如何做到 \(O(1)\) 或 \(O(log)\) 把 \(s\) 跳到 \(k-1\) 个字符的位置,能做到的话之后借用预处理的向下走同一字符边的数组就能查到最后一个匹配的位置,更新 \(mat\) 并计算答案。
一种做法是倍增 \(O(log)\) ,或者长剖 \(O(1)\),但是还有更简单的办法。
考虑记录trie上每个节点对应是哪个串的一部分,也处理处来每个串每个位置在trie上的位置,设当前 \(s\) 匹配到的节点是 \(cur\),那么直接找到 \(cur\) 所在的字符串,跳跃到这个字符串 \(k-1\) 字符在 trie 上的位置即可。
注意特判 \(k=1\),这个时候需要remake,直接把 \(cur\) 设置为1即可。
复杂度 \(O(n|\sum|+m)\),简单好写
Day17D1T2
逆天推式子题,题解推式子过程写的依托,只有结果正确,自己推了一中午才推出来正确的过程,拜谢 zhiyangfan 和 zyc070419 的帮助。
不难发现每个点恰好会伸出去一条无向边,于是的 \(G\) 的 (◕‿‿◕) 子图实际上是一个基环树(森林),并且不难发现所有的基环树都是有一个重边的基环树,否则会产生矛盾,若干个不同的数中有两个最大值/jy(我为什么就看不出来捏)。
所以实际上就是求图中出现恰好 \(k\) 个重边的方案数,直接算很困难,不妨二项式容斥,算至少 \(t\) 个重边的方案数。
考虑现在钦定了某 \(t\) 个重边,为了方便起见,给这 \(t\) 条边按从小到大顺序排序,那么原图中的边需要满足以下条件。
1 . 如果就是某条重边,那么没有限制。
2 . 如果两端点在某两条重边中,设两条重边的权值是 \(e_i,e_j\),那么这条边的权值 \(w\) 要满足 \(w<e_{min(i, j)}\)。
3 . 如果只有一个端点在某条重边 \(e_i\) 中,那么只需要满足 \(w<e_{i}\)。
4 . 都不满足,那么这条边并不会对图产生影响,也没有限制。
现在计算对于重边 \(e_i\) 有多少条边的 \(w\) 需要满足 \(w<e_i\)。
一种是一个端点在 \(e_i\) 中,另一个端点在 \(e_j(j>i)\) 中,这样的边有 \(2 * 2 * (t-i)\) 条。
另一种是一个端点在 \(e_i\) 中,另一个端点不属于任何一个重边,重边覆盖了 \(2t\) 个点,所以这样的边有 \(2 * (n-2t)\) 条。
加起来就是 \(2n-4i\) 条边。
一共受到影响的边就是 \(\sum_{i=1}^{t}2n-4i = 2tn-2t^2-2t\),因为还有 \(t\) 条重边自身,所以再加上 \(t\) 得到 \(2tn-2t^2-t\)。
那么有至少 \(t\) 个重边的图数量就可以算了:
然后就是推式子了……
最右边这个连乘可以写作 \(\prod_{i=1}^t \frac{((\sum_{j=1}^{i}(2n-4j+1))-1)!}{(\sum_{j=1}^{i-1}(2n-4j+1))!}\),发现这个式子是可以上下隔项相消的,最后变成了 \(\frac{(2nt-2t^2-t)!}{\prod_{i=1}^{t}(2ni-2i^2-i)}\),这个东西可以拆成双阶乘,又变成了 \((2nt-2t^2-t)!\frac{(2n-2t-3)!!}{t!(2n-3)!!}\)。
最右边最终的形式前面的阶乘可以与前面的组合数消掉,这个式子最终变成了:
然后回到二项式反演上,首先是二项式系数 \((-1)^{t-k}\binom{t}{k}\),然后是选出来这 \(t\) 条重边并排序的方案数是 \(\binom{n}{2t}(2t-1)!!t!\)。
然后把他们全乘起来!
再消一些项:
因为求的是概率,所以还要乘上 \(\frac{1}{({\frac{n(n+1)}{2}})!}\),最终的式子:
结束了,复杂度 \(O(n)\)。
敲公式累死了。
Day21D1T3
卡空间题,但是推式子还是蛮有意思的。
题目要求的东西看上去相邻两项的差别不大,不妨差分。(不妨?)
令 \(g(n)=\sum_{1\leq a<b\leq n}[gcd(a,b)==1\and a+b==n]\frac{1}{ab}\)。
注意 \(f(n\leq 2)\) 需要特判。
接下来考虑计算 \(g(n)\),把 \(\frac{1}{ab}\) 换成 \(\frac{\frac{1}{a}+\frac{1}{b}}{a+b}\),相消后可以得到 \(g(n)=\frac{1}{n}\sum_{a=1}^{n}[gcd(a,n)==1]\frac{1}{a}\)
然后常规的莫凡一下,得到 \(g(n)=\frac{1}{n}\sum_{d|n}^{n}\frac{\mu(d)}{d}\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\frac{1}{i}\)。
预处理逆元前缀和,莫比乌斯函数可以直接筛出来所有 \(n\) 的质因子然后二进制枚举计算。
复杂度 \(O(n+T(\sqrt n+2^{w(n)}))\),轻松过。
Day22D1T2
推式子简单但是相当卡常的逆天卡时间题,写一下通过这题的全流程吧。
首先看到这题数据范围不大,作为一个数位DP背景的题数据范围只有 \(10^18\),考虑爆搜,搜出来发现只有约 1e7 个本质不同的状态,可以和暴力拍上,可以很遗憾 200ms 的时限一个测试点都过不去,据说有人把这个爆搜+记忆化就过了,不能理解。
接着考虑转成复杂度有理有据的东西,考虑写成 DP,可以分成两大类来做,设上限串长度是 \(len\),一类是长度 \(<len\) 的,另一类是长度 \(=len\),分类是因为第一类不需要考虑卡上界,而第二类需要。
发现第一类对于任意上界串只和上界串的长度有关,可以简单打表,并且只需要分 \(d=0\) 和 \(d\neq 0\) 两类讨论,轻松打个 \(2\times 18\) 的表。
那么只需要考虑第二类的 DP 了,先枚举前缀有多长和上界串相等,然后枚举相等部分后一位不卡上界,之后就随便填了。
随便填只需要枚举数字 \(d\) 的数量,其他的数字都不能超过这个上界,简单背包就做出来了。
这样复杂度变成了单次 \(O(10^2(log_10 V)^4)\),显然不能通过。
实际上我们只关心其他数字已经确定的出现次数与枚举的 \(d\) 的出现次数的差值,并且可以排序,这个本质状态数是非常少的。
记忆化一下即可,复杂度 \(O(能过)\)。
Day23D1T3
可能比较套路,但是对我来说并不套路的ds。
首先有 \(a_{t,i}=max_{j=i-t}^{t}a_{0, j}\)。
直接拆 \(a_{t,i}\) 很难,正难则反,考虑什么时候 \(a_{0,i}\) 会产生贡献。
对于 \(a_0\) 跑一下单调栈,求出来每个数成为最大值的区间 \([l_i, r_i]\)
考虑对于某个询问 \(l, r, t\),\(a_{0,i}\) 贡献到的位置 \(j\) 需要满足条件:\(max(i,l,l_i+t)\leq j\leq min(i+t, r, r_i)\)。
如果直接把所有 \(l_i\leq j\leq r_i\) 做扫描线复杂度最坏是 \(n^2\) 的,考虑实际上只需要加入两边较少的那一些即可,也就是加入 \(min(i-l_i, r_i-i)\) 个元素即可,具体的加入方式可以参考我的代码。
这样复杂度是 \(O(nlogn)\) 的,证明可以参考我曾经的博客,利用到了笛卡尔树的知识。
那么再加上扫描线的一个 \(log\),总复杂度是 \(O(nlog^2n)\) 的,但是很难卡满跑的非常快。

浙公网安备 33010602011771号