2023 NOIP 集训

Sdsc7.14

t1

一个小区,有 \(n\) 个人要住进 \(m\) 个房子,一个人有邻居的满意值是 \(a_i\) ,没有邻居的满意值是 \(b_i\) ,求怎么安排使得总满意值最大,需要让每个人都住进房子。

这是一个经典贪心问题——by Qingyu ,我们先假设所有人都没有邻居,然后按 \((a_i-b_i)\) 从大到小排序,将这些人作为有邻居的,直到所有人都能住进房子。

t2

给定 \(2n\) 个点,点有横纵坐标,我们称 一对点是好的,当且仅当横坐标相同或纵坐标相同。

最大化好的配对的数量,要求每个点都在一个配对中。

构造二分图的好题,完全不会。

应该是套路吧,二分图的左半部分对应每个点的横坐标,右半部分对应纵坐标,对于每个点 \((x_i,y_i)\) 连一条 \(x_i\to y_i\) 的边,问题转化为如何最大化 两条相连的边 的数量。

每个连通块都是独立的,有个结论是每个连通块都可以取到上界:\(\lfloor\frac{m}{2}\rfloor\)

构造方法是,每个连通块,在 dfs 树上,从下至上构造,类似这样,实际上很像dp对吧。

T3

给定一个 \(n+1\) 的条边的图,求 \(u,v\) 之间路径的个数。

树上两点间的路径是唯一的,多了两条边,路径数量最多为4:

  • u - v
  • u - a-b -v
  • u - c-d -v
  • u - a-b - c-d - v

只需要判断是否会出现下述三种情况,本质上是什么呢,本质上是树上询问 \((u,v)\)\((a,b)\) 路径是否相交,如果相交才可以通过简单路径过去。

这个问题是一个经典问题,最为简单的方式是 dis(a,b)+dis(c,d)=dis(a,c)+dis(b,d)=dis(a,d)+dis(b,c) ,复杂度为 \(O(\log n)\)

T4

给定一个长度为 \(n\) 的序列,定义 \(F(A)=\max ((a_1\&a_2\&...\&a_k)+(a_{k+1}\&a_{k+2}...\& a_n))\)

你可以至多进行一次交换 \(a_i\) 求 F 最大值。

也是 与 运算的老套路了,我们定义关键点当且仅当这个点对答案有贡献(负贡献):\(f(i)\ne f(i-1)\),不难发现这样的点只有\(\log\) 个。

由于不确定 \(k\) ,所以我们求一遍前缀关键点和后缀关键点,然后分类讨论。

  • 交换两个非关键点,没有意义。因为与运算不会让答案变大
  • 交换两个关键点,大力枚举 \(k\) 和前后缀关键点,复杂度 $O(n\log ^2) $
  • 交换一个前缀关键点和后缀非关键点
    • 此时后缀的总值为 \(f(k+1,n)\&a_i\)
    • 也就是说,我们固定 \(i\) ,那么后缀的值已经确定了,无论选哪个 \(j\) 都一样。
    • 那我们肯定选对前缀答案最有利的 \(j\)
    • 注意 & 的性质,我们固定一个关键点 \(i,f(i+1)\) 的取值也只有 log 种(\(f\) 是单调不升的),我们枚举 \(i\)\(f(i+1,k)\) 即可,记答案 \(v=f(1,i)\&f(i+1,k)\) ,同时你也得到了一个最大的 \(k\)(能保证后面的数尽可能大) 。
    • 然后 \(O(n)\) 计算 \(v\&a_j,k+1\le j\le n\) 的最大值即可。总复杂度 \(O(n\log^2)\)

Sdsc 7.15

T1

图的模块度

简单模拟。

T2

一个数列 \(f_0=f_1=0\),

\(f_i=f_{i-2}\times f_{i-1}\times i\) ,求 \(f_n\) 的因数个数、\(n\le1e6\)

大家都知道因数个数等于指数加一连乘积对吧,所以我们先线性筛出所有 n 以内的质数。

考虑外层枚举质数 \(p\) ,定义 \(g_{p,i}\) 表示 \(i\) 的质因数分解后,\(p\) 的指数是多少,\(h_{p,i}\)\(f(i)\) 质因数分解后 \(p\) 的指数。

得到了 \(h_{p,i}=h_{p,i-2}+h_{p,i-1}+g_{p,i}\) ,很烦,因为有后面的 \(g_{p,i}\) 而不能矩阵快速幂。

不过发现 \(g_{p,i}\) 实际上只有当 \(i\)\(p\) 的倍数时才有值,即 \(\frac{n}{p}\) 个位置有。

所以我们对于这些位置暴力转移,剩下的fib矩阵快速幂,这样复杂度是:\(O(\sum_{i=2}^{i\in P} \frac{n}{i}\log i)=O(n*e*\log n)\)

发现我们完全没啥必要在这里做矩阵快速幂,提前预处理出 \(A^i,i\in P\) 即可。

这样复杂度是 \(O(π(n) \log n+ O(n\times e))\)

Summary

  • 对于不能直接做矩阵快速幂的情况,多出来的部分可能个数不会很多。

T3

大模拟

T4

noip再补。

Sdsc 7.16

T1

给定一张图,有点权和边权,求出 \(max_{x,y}\{max(w_x,w_y)*dis(x,y)\}\) ,\(n\le1e5\)

因为要求最大值,所以不必麻烦严格按照规定做,我们枚举每个点,统计 \(max\{w_x*dis_{max}\}\) 即可。

\(dis_{max}\) 表示 \(x\) 能到的最远距离,有一个非常重要的结论是最远的这个点一定是树的直径两端点之一(下文也有,否则一定不是树的直径。于是先求一遍树的直径并找出两端点 \(a,b\) ,$dis_{max}=max(dis(x,a),dis(x,b)) $ 。

T2

给定一个无根树,等概率随机加一条边,每次给出 \(x,y\) ,询问 能使 \(x,y\) 在一个环里的情况中,环大小的期望是多少?\(n\le1e5\)

其实等价于分别求,能使这俩在同一种环的情况数,以及环长度的和。

需要分类讨论,两个点有祖先关系和没有祖先关系。

没有祖先关系的情况是简单的,情况数是 \(siz[x]*siz[y]\) ,大小和是 \(dis(x,y)*(siz[x]+siz[y])+\sum(dis(1,u)-dis(1,x))+\sum....+1*(siz[x]+siz[y])\)

对于有祖先关系的情况,方案数是 $siz[y]*(n-siz[x]) $ ,大小和,我们要额外记 \(D(x)\) 代表以 \(x\) 为根的子树,所有和 \(x\) 相连的线段长度和,发现这东西是树上前缀和的前缀和所以是可做的,故大小为 \(D(1)-(D(x)+dis(1,x)*siz[x])+D(y)+1\)

有点类似换根dp,所以官方做法其实是换根dp。

Sdsc 7.17

T1

求满足长为 \(k\) 序列数量:

  • \(a_i\in[1,n]\)
  • \(a_i\) 有序且互逆
  • \(\forall x\in Z+\) ,以 \(a_i\) 的任意顺序作为排列,依次取模后结果相同。

手摸样例发现:x%a%b=x%b%a 的充要条件是 \(a\mid b\)

我们令 \(a_0\) 为最小的 \(a\) ,猜测充要条件是 \(a_0|a_i\)

于是我们枚举 \(a_0\) ,数量个数就是 \(\binom{\frac{n}{a_0}-1}{k-1}\) 。复杂度 \(O(n)\)

T2

Sdfz 8.10

Road Reform

给定一张图,构造一个生成树使得最大边权恰好为 \(k\),你可以通过若干次+1的操作或-1的操作,来完成,求最小操作步数

考场5min出正解调不出来了,好像是最小生成树没排序。

两次最小生成树,一次强制把k的前驱的边给加上,一次强制把k的后继的边给加上,当然可以取等,答案为两者最大值。

Gardening Friends

给定根为1的一棵树,移动根的代价是 \(c\),每条边的权值是 \(k\) ,定义一棵树的价值为根节点到子节点的最长距离,求价值最大值。

关于树的直径有一个极其简单的引理,同时也是两次dfs操作的理论基础,(当时)却是不会。。。

引理:树上任意一个点的最远点一定是 树的直径的两端点之一。

证明:反证法分三类讨论即可。

引理2:一棵树上多个树的直径,其关于根的深度有且只有两种。

那这样我们两(三)遍 dfs,求出1到每个点的距离 \(dep_i\) ,再求出 \(x\) 到每个点的距离 \(d1_i\) ,再求出 \(y\) 到每个点的距离 \(d2_i\)

答案就是:\(Max\{-c\times dep_i+max(d1_i,d2_i)\times k\}\)

T3,4

扫描线和二维数点

Sdfz 8.15

T1 :Zero path

特别好的一道结论题,(其实考场上最后想到了

给定一个网格,网格上数字为1或-1,问从左上角到右下角是否有一条路径(只能向下或者向右),使得和为0.

遇到这种带有特殊性质的:点为1,-1:一定要考虑这个性质所带来的特殊结论,往往都是突破口。

我们注意到,一个点往右往下走,要么两个仍保持不变,要么相差2,另外如果n+m 是奇数则一定无解,考虑是偶数的情况。

令 A 为最短路的路径,B为最长路的路径,存放的是怎么走(Right or Down)。因为集合相同,那么我们可以不断通过交换相邻两个数来从A到B。

交换相邻两个数,对权值和产生的影响一定是+-2,又因为是偶数,所以最小值——最大值的过程中一定经过0,只需要判断最小值是否<0,最大值是否>0即可。

手模样例一般就可以得出结论

T2 P1034 [NOIP2002 提高组] 矩形覆盖

妈的怎么远古题都是傻逼搜索题呀。

T3 CF600E

dsu on tree/线段树合并 板子题

T4 篝火晚会

傻逼中模拟。

BCT23.8.18

本场 \(n,m\) 同阶,均为 \(1e5\) 级别。

T1

给定一个序列 \(a_n\) ,要求按顺序种上太阳,初始阳光为0,种下并不花钱,但是每秒会生产 \(a_i\) 的阳光,注意 \(a_i\) 有可能是负数,每秒可以选择种下下一棵或者等待,若某一时刻手里的阳光为负数则输出-1,求最短时间。

好像还真的是简单的反悔贪心,边输入边记录一个前缀最大值,如果当前的阳光为负数,那么不断增加这个前缀最大值直到大于等于 \(0\) ,额外增加的时刻就是增加前缀最大值的次数。

考场十五分钟切了。

T2

给定一个序列 \(a_m\) ,每个数大小不超过 \(n\) ,你有一个大小为 \(k\) 的容器,支持插入和删除操作,删除指定删掉最早访问的元素,你需要依次访问序列的数,注意到若此时容器内有当前要访问的元素则可以不必再插入,依次输出 \(k=1...n\) 的插入次数。

若当前序列为 1,2,3,2,1,2k=1 时答案显然是 6

k=2 时,第二个 \(2\) 和第三个 \(2\) 不必进入,答案为 \(4\) .

k=3 时,发现此时只需要把 1,2,3 给插进来就行,答案为 \(3\)

记录当前点上一个出现位置为 \(pos[a[i]]\) ,如果 \(i\) 可以在 \(k=x\) 利用到 \(pos[a[i]]\) ,那么需要保证中间数的个数不超过 \(x\),仔细想想,如果 里面有重复的数字? 根据这条规则,其对应的 \(x'\) 应该比 \(x\) 小,所以在 \(k=x\) 的条件下,里面重复的数字都可以利用,所以本质上 \(x\) 是中间不同数的个数。用主席树维护即可(HH的项链)。

求出 \(x\) ,相当于这个点对 \(ans[1]\) ~ \(ans[x]\) 都加 \(1\) ,再用个差分就做完了。

考场以为12点收卷于是调不出来摆烂,得知是半收卷,最后十分钟做完的,主席树的 \(n\) \(m\) 写反了。

T3

给定序列 \(a_n\) ,要求划分为若干段,每段长度为 \(1\) 或者 \(2\),使得最大值减去最小值的差最大。

我愿称为 线段树上区间 \(dp\) ! 总感觉做过一道类似的题。(不过这不就是动态dp吗——23.8.29)

我们发现 push_up(p) 本身就是一个非常像区间 \(dp\) 的东西,将两个东西合并。

\(t(l,r,0/1,0/1)\) ,表示该线段树上的区间 \([l,r]\) 已经覆盖,左边界是否为左端点,右边界是否为右端点,的最大值最小是多少?

那肯定是单个呀,一遍O(N)求最大值就完了。

话虽如此,但我们为了支持修改,就只能设这种在不用修改下显得非常智障的东西。

\(t(l,r,0,0)=Min\{max(t(l,mid,0,0),t(mid+1,r,0,0)),\ max(t(l,mid,0,1),t(mid+1,r,1,0)) \}\)

诸如此类,写在 push_up() 里_。

那么我们只需要 枚举最小值,由于一次只会增加一个最小值,那么我们每次只需要单点修改最小值所在的点变为正 INF。

具体的,把长度为1和所有长度为2的2n个元素排序后,从小到大,依次删除。

  • 对于单个的元素,左闭右闭肯定是INF,左开右闭和左闭右开根据是否在边界上决定是否为   a[l]+a[l+1]或者 a[l]+a[l-1] 还是 INF

  • 对于两个的元素,强制让他俩拆开就行,对于 \(l\) ,左开右闭是 合法的,其余都是非法的,对于 \(r\) 同理。

为什么是对的,在没有修改的情况下,肯定选不到开区间的点,在修改后,有些地方变成正无穷,就必须使用这些点了。

T4

给定一棵树,点有点权,树上一条路径 \((u,v)\) 的价值是 \(\sum (x*w_k)\) ,其中 \(k\) 是路径上的点, \(x\) 是路径上小于等于 \(w_k\) 的点的个数。

求所有路径的价值和。

一眼考虑贡献!但是考场上想的是考虑点 \(u\) 的贡献,发现很难做。

正解是考虑 \((u,v)\) 的贡献,  设 \(w_u\le w_v\)  ,那么贡献是包含 \(u\), \(v\) 的路径数量乘上一个 \(w_v\)

枚举点 \(v\) ,分类讨论。

  • \(u\)\(v\) 子树内,那么 dfs 序上二维数点就行,数有多少个权值 \(\le w_v\) 的。
  • \(u\)\(v\) 祖先,那么 dfs 的时候用一个平衡树来维护。
  • 剩下的情况,也就是两者有一个 \(lca\) 的情况,就是整棵树 \(\le w_v\) 的减去上面两者即可。

所以考虑贡献有没有什么技巧。

BCT 8.19

T1

因为缺省源内 \(N=1e5\) 导致白丢 \(30pts\) ,警钟长鸣。

T2

给定 \(n\) 个字符串,从中选出 \(k\) 个字符串,你的目的是让这 \(k\) 个字符串中某两个的最长公共前缀的最大字典序最小。 \(n\le10^5\)

赛时错误的想法是依次枚举每一个点作为最大LCP,正确的思路是逐位确定答案。

为什么呢?发现这个答案肯定是可以逐步确定的对吧。

从头分析,一个点 \(u\) 能作为答案,那么选中的 \(k\) 个点该怎么分配呢?

  • 对于字典树左边的点显然是可以任意选的

  • \(u\) 子树的点,不能使他们产生新的,更深的lcp,所以每个儿子只能选一个。而且至少选两个儿子。

  • \(u\) 到根链上右边的点,也是不能让他们产生新的lcp,所以每个儿子只能选一个。

假设当前已经选中了答案的前 \(k\) 位,判断第 \(k+1\) 位是否能为 \(c\) ,当且仅当:

  • 之前的选中的点

  • 当前点所代表字符串的个数

  • 1~c 位全部选

  • c+1位到26位只能选一个

  • 这些和加起来 \(\ge K\)

那么可以选择这一位,并且将累计的 \(num\) 减去 第 \(c\) 位全部选的情况,  \(K\) 同样可以减去 超出的值,递归到下一层。

直到只需要加上 大于等于 \(2\) 个 只能选一个的儿子和本身,就可以 满足要求,便停止递归。

实现起来还蛮复杂的,因为是随机的数据,所以std也没判断 要求大于等于2个儿子和本身。把小王Hack了(

逐位分析。

T

给定一个长度为 \(n\) 的字符串,对于每一个后缀,求出他们能有多少种:“AABA”类型的方案,其中AB均不为空。 \(n\le10^5\)

关键在于转换,显然我们要枚举 \(A\) ,因为\(A\) 一定是原字符串的一个后缀,然后再找前缀= \(AA\) ,而且长度 \(\ge 3|a|+1\) 的后缀数量。

考虑将所有后缀 按照哈分+二希排序,得到按字典序排序好的字符串,我们再枚举 A ,那么所得到的 以AA为前缀 一定是在一个区间内,这样就可以哈分+二希找出这段区间,具体地,找出第一个前 \(2|A|\) 的 Hash 大于等于 \(2A\) 的,再找出第一个 前 \(2|A|\) 的Hash 大于 2A的,但是怎么感觉这样不满足单调性呀,你想想因为有个取模所以按字典序排完,hash值也是排好的吗?

然后又要保证长度,就是一个 simple 的二维数点问题啦。时间复杂度 \(O(n \log^2)\)

BCT 8.20

T4

给定一张图,每个点有点权 \(a_i\) ,但是相连的两个点所选择的点权必须相等,你要对于每次删除一条边 ,求出此时可以选到自己的点权的点有多少个。

详情揭秘如何 \(O(1)\) 支持插入,删除,集合众数的出现次数。

  • 维护两个数组 \(f_i\) 表示 \(i\) 的出现次数, \(g_i\) 表示 出现次数为 \(i\) 的元素个数。

  • 对于加入元素 \(x\)g[f[x]]--,f[x]++, g[f[x]]++,此时 \(ans=max(ans,f[x])\)

  • 对于删除元素 \(x\)g[f[x]]-- , 此时若 g 等于 \(0\),那么 \(ans=ans-1\)f[x]--g[f[x]]++

那这样就好做了,如果这条边不是割边,一定不会影响连通性,答案就是不删边的答案。

割边的情况,我们将边双缩点后的树形图上 dfs,结合上述我们发现的牛逼小清新数据结构,以及dsu on tree,就可以 \(O(n \ log n)\) 做了。

不过 dsu on tree 不敢写。要是我很会就不会写2h线段树合并了。

好好好,std 250行是吧。

BCT8.21

T1

7层 分层图上跑最短路。

或者叫,最短路图?

T4

给定 \(n\) 个数 \(a_i\) ,若两个数 \(a,b\) 满足 \(\gcd(a,b) \ge m\) ,则可以选择 \(a,b\) 其中一个删去,求最大的 \(m\),使得经过 \(n-1\) 次删除后只剩下一个点。\(n\le10^4,a_i\le10^7\)

  • 类似于“每次删除一个,最后剩下一个“的具象化结构实际上是一棵树。最后剩下的点就是树根。

  • 那我们最终要求的最小 \(m\) 实际上就是树上 最小的一条边。

  • 类似最大生成树,不断从树上连边,关键在于判断连通性——并查集。

  • 但是边的个数是 \(n^2\) 级别的,再加上一个 \(log\) 的排序。

  • 发现 \(a_i\le 10^7\) ,一个数的因数个数是 $O(\sqrt{n}) $ 级别的,可以接受。于是把所有数的因数存到 vector<> 里,不会MLE。

  • 最刺激的地方来了,不能完全模拟 \(kruskal\) 最小生成树的建法,只需要模拟两个点是否联通即可。也就从大往小枚举边(gcd),看看其两边的点是否在生成树(并查集)内,如果不在就加进来。直到只剩一个并查集。

  • 错了!自己考场上写的就是正解,只是没调出来。

  • 从大到小枚举 公因数,不断找两个公因数的倍数合并。因为有

后面是啥?——9.24

BCT8.22

T1

给定一棵树,若干个点可以选择,选择其中 \(m\) 个点,使得其中 最远的两个点距离最小。\(n \le 3000\)

  • 是不是可以淀粉质呀(雾

  • 一眼二分答案(距离),check怎么写?

  • 考虑树形 \(dp\)\(dp_{u,i}\) 表示以 \(u\) 为根的子树内,选择了 \(i\) 个点,距离最远的一个点的距离。

  • 很难转移,考虑状态结果互换。

  • \(dp_{u,i}\) 表示以 \(u\) 为根的子树,距离最远的一个点的距离是 \(i\) ,最多能选择多少个点。

  • 转移: $dp_{v,k}\to dp_{u,max(k,j)}\ $ ,具体地, \(j\) 枚举最长距离, \(k\) 枚举子树的距离,即 \(mid-\)

BCT8.23

T3

给定一张有向图,求出一棵满足各点到 \(1\) 最短路长度不变的 最小生成树。

  • 最短路图。

    完全没听过呀,只需把所有 \(d_v=d_u+w\) 的边给加进来就行。

  • 有向图最小生成树

    完全没学过呀,有一种算法叫做“朱刘算法”求最小树形图,好好好没听过。

    不过我们完全不需要用他,跑 \(kruskal\) 就行了。

T4

\(n\) 个人在玩击鼓传花的游戏,有两个花,初始分别在 \(a,b\) 手里,在 \(T\) 轮游戏中,每次需要把其中一朵花传递到 \(s_i\) 手中,另一朵花不能操作,求最小操作次数。

  • 感觉是 \(Smeow\) 之前在日照出过的题?

  • 考虑一个 \(O(n^3)\) 暴力,设 \(dp_{i,j,k}\) 表示 第 \(i\) 轮游戏,第一朵花在 \(i\) 手里,第二朵花在 \(j\) 手中的操作数。

  • 显然第 \(i\) 轮手里其中一朵花一定在 \(s_i\) 手里,另一朵在 \(j\) 手里,所以优化到 \(O(n^2)\)

    有转移方程 $dp_{i,j}=\begin{matrix} dp_{i-1,j}+|s_{i-1}-s_i| ,j \ne s_{i-1} \ Min{dp_{i-1,k}+|k-s_i|},j=s_{i-1} \end{matrix} $。

    上面那个复杂度是 \(O(1)*n\) ,下面那个复杂度是 \(O(n)*1\)

  • 还挺复杂的,考虑怎么做到 \(O(n\log n)\) ,用线段树优化。

    感觉是为数不多的用线段树区间修改优化 \(dp\) 的,上面那个显然就是一个区间加法。加上一个 \(|s_i-s_{i-1}|\) 的常数。——后面9月校内模拟赛又出了一个Bakery

    下面那个玩意再拆一拆,把绝对值去掉:

    • \(dp_{i,s_{i-1}}=Min\{dp_{i-1,k}+|k-s_i| \}\)

      这样就可以对 \(k<s_i\) 的,求 \(Min \{a_i+i\}\) ,对后面的,求 \(Min\{a_i-i\}\) ,好像比较困难,还去u群问了,其实很简单,你在求 \(dp_{i-1}\) 的时候是知道 \(s_i\) 是多少的,求的时候记录一下 minn 即可。后面是一个单点修改、

    这样,不需要开二维数组,只需要用一个线段树维护,支持上述三种操作。最终答案即 \(\min dp_j\)

    挺牛逼的题,有空就实现一下。

BCT8.24

T2

最大全1子矩阵问题

记录每个位置往上走最长有多少个 \(1\),可以从上一行转移下来 。转换成直方图最大子矩阵,单调栈即可。

单调栈:记录每个位置开始向右能扩展多少个矩形。每次单调栈进来一个较小的,都把比他大的弹出。每一步统计选 \(i\) 的面积大小。注意在最后新加入一个高度为 \(0\) 的。

笛卡尔树也可以,复习一下:

将下标作为 \(val_i\)\(h_i\) 作为 \(rnd_i\) 建立小根堆,建立一棵笛卡尔树,每个节点都是一段连续的区间,且子树的根节点的 \(val\) 就是这段区间的最小高度,乘上这个点所代表区间的长度即可。

T3

  • 走到第 k$ 轮的概率是 0.6^k$ ,所以全排列在随机数据下跑得飞快。

  • 从后往前枚举,增加在第 \(i\) 位,增大到 \(x\)

T4

博弈论

BCT8.25

BCT8.26

T4

一张 \(n*m\) 的网格,可以黑白染色,当某一行或者某一列全为 \(0\) 或者全为 \(1\) 时,对答案有 \(1\) 的贡献,求贡献为奇数的网格方案数。\(n,m\le1e6\)

  • 枚举至少打破多少个条件。

    \(\sum(-1)^i*...\)

    打破刚好奇数个条件的答案?

    \(\sum(-2)^{i-1}\)

    刚好打破偶数个条件?

    \(\sum-(-2)^{i-1}\)

  • 容斥系数?

    最普通的:枚举至少打破0个,1个方案,2个方案,,,,n个方案。用系数乘起来。

  • 至少打破0个为什么是1?

    刚好打破0个的方案——1。只会在这里统计,且是最后一次有机会统计的地方。

  • 至少打破1个

    刚好打破1个的方案——在0处统计,在1处统计,希望他统计0次,而在0处统计1次,故-1

  • 刚好打破2个

    应该统计0次,但是在0处统计 \(C(1,n)\)

    • 分类讨论

      打破 \(i\) 个行:\(\sum_{i=1}^n (-2)^{i-1}*C(i,n)*2^i*2^{(n-i)*m}\)

    • 列对称

    • 都打破

      \(\sum\sum(-2)^{i+j-1}*2*2^{(n-i)*(m-j)}\)

  • 二项式定理

    $\sum $

Sdfz 9.23

T1

给定一棵 二叉树,初始时刻 \(1\) 号点感染了病毒,每一回合病毒都会传播一层,但是每一回合你都可以删掉一个点来阻断传播,求能保留的最多点(不算删掉的点)

如果看到二叉树是好做的,看不到是没法做的。

贪心贪子树大小肯定是错的,和树的结构(链)是有关系的,所以dp求解。

T2

给定 \(n+1\) 个数 \(a_i\)\(n\) 个数 \(b_i\) ,对于每个 \(i\) ,求出删掉 \(a_i\) 后,剩下的数两两配对,使得 \(a_i-b_j\) 最大值最小。\(n\le1e5\)

显然要排序,对答案有影响的只有最大的那一个,所以配对一定不会相交。删掉一个数,左边的仍是直上直下的配对,右边的是 \(b_i 和 a_{i+1}\) 配对,所以我们预处理一个前缀后缀最大值就可以 \(O(n)\) 做了。

差点死因:用 map 记录下标,但是显然这不是个排列。

T3

\(n\) 棵树,每棵树有高度 \(h_i\) ,有 \(m\) 条边权为 \(w\) 的双向边连接两棵树,但是在飞翔过程中会下降 \(w\) ,你需要保证飞行是合法的,即不能落在地上,也不能超过树顶。起点是第一棵树的 \(x\) 高度,终点是第 \(n\) 棵树的最高点,求最短路。\(n\le1e5,h_i\le1e9\)

最暴力的方法是每棵树都建出 \(h_i\) 个点,复杂度 \(O(h_i(n+m \log m))\)

但实际上这题是个贪心,我们先考虑起点高度是 \(0\) 怎么走,发现只要走到 \(h_u=w\) 时就直接飞行到 \(h_v=0\) 即可,如果再往上走,那么有可能还要再往回走,因此这样是最优的。对于走不到的情况,在加边过程中舍弃即可。

如果高度是 \(x\) ,那么会往下走,走到 \(h_i+w\) 一定是优的。

如果能正常飞,那就不需要走。

T4 Bakery

区间加法线段树 优化dp

\(n\) 个数分为 \(k\) 段,使得总价值最大,定义一段的价值是该段不同数字的个数、 \(nk \le 1e5\)

不加优化的状态方程很好想,

\[dp_{i,j}=Max(dp_{k,j-1}+val(k+1,i)) \]

但一上来先打主席树就彻底输了,瓶颈压根不在于处理区间不同数个数,暴力做枚举就行。

线段树优化dp?后面的东西在括号里面,也不能做。

考虑贡献

当我们求到一个数 \(a_i\) 时,\(a_i\)\(dp\) 有贡献的是 \(dp_{[pre+1,i-1],k}\) ,且贡献为 1 ,所以线段树实现一个区间加法+区间最大值就可以了。

是不是挺像莫队?

Nfls 9.25

Booms 60 but 0 how fucking fhq+bit?

T1

给定一个长度为 \(n\) 的字符串,多次询问区间 \([l,r]\) 的最长回文子串。\(n\le 3e5\)

遇见回文串,可以先 \(manacher\) 简化一下,并求出每个点的最长回文半径 \(p_i\)

暴力的做法是,每次在区间内枚举 \(j\) ,答案就是 \(Max\{ min(p_i,j-L,R-j)\}\)

实际上这就是一个 最小值最大 问题,考虑二分答案 \(ans\) ,那么 \(j\) 所在的区间一定是 \([L+ans,R-ans]\) ,且要满足这个区间内存在一个值等于 \(p_i=ans\) ,也就是,只需要保证 \(\exist \ p_i\ge ans\) 即可,因为 \(p_i\) 是静态的,所以直接 \(ST\) 表维护即可。

\(manacher\) 后的新串操作需要注意前后对应关系。

所以根本不需要树套树对吧————

T2

给定一个长度为 \(n\) 的小写字母字符串,其中有些位置是 ? ,求有多少种方案能使得整个串中 "sakana""chinanago" 两个串的出现次数相同。 \(n\le 1e4\)

首先我们发现 两个字符串是完全不交的 ,因此我们有暴力 \(dp_{i,a,b}\) 表示 有 \(a\) 个字符串1,\(b\) 个字符串2 的方案数。

但这样是三次方的,对于“相等”的问题,一种常见的套路是 改状态设计为 \(dp_{i,j}\) 表示 两种字符串的差为 \(j\)

转移有

\[dp_{i,j}= \begin{matrix} dp_{i-1,j}*26-[str1]*(dp_{i-6,j-1}-dp_{i-6,j})-[str2]*(dp_{i-9,j-1}-dp_{i-9,j}) \ \ a[i]= ? \\ dp_{i-1,j}+dp_{i-1,j-1}+(dp_{i-1,j-1}+dp_{i-1,j}) \ a[i]\ne ? \end{matrix} \]

孙老师表示完全不能理解呀,被他一说感觉加深了对dp的理解呢。

首先你新加一个字符,初始值是从上一位转移过来的,如果此时生成一个新串,那对 \(j\) 这一维是有贡献的,所以还要从 \(dp_{i-6,j-1}\) 转移过来,但是因为中间全部合法的部分算了两遍,所以减去一个 \(dp_{i-6,j}\) 。孙老师疑惑这里为什么不是 \(j-1\) 呢,我们考虑他的实际意义,实际上后面少了一个系数 \(*1\) ,意味着后面这几位都固定好了——。

T3

给定一张图 ,和参数 \(q\) ,求走 \(1...q\) 条边的最长路,\(n,m\le1e3,q\le1e9\)

\(q\le m\le1e3\) 时,暴力做就好。

\(q\ge m\) ,我们一定可以走到一条最大的边,然后不断在这条边上走,使得总答案最优。而前面的过程一定是从1开始的最长路。

于是我们暴力枚举 \(i\to j\)

T4

Nfls 9.26

T1 有限小数

求出有多少对 \((x,y)\) 满足 \(\frac{x}{y}\) 是十进制有限小数,\(x,y\le1e11\)

小学数学经典结论,十进制有限小数等价于 \(\frac{a}{2^p5^q}\)

这里还没有考虑到约分,于是有 \(\frac{ak}{2^p5^qk}\) ,需要满足 \(k\) 既不是 \(2\) 的倍数也不是 \(5\) 的倍数。

\(2^p5^q=a_i\) ,答案即为 $\sum_in\sum_k \lfloor\frac{n}{k}\rfloor,a_i\le n,k\mod 2,5 \ne0 $ 。复杂度 \(O(e*n^2)\)

考虑更换枚举顺序,外层枚举 \(k\) ,则有 \(\sum_k^n d* \lfloor\frac{n}{k}\rfloor,d是合法a_i 的个数,k\mod 2,5 \ne0\)\(d\)\(a\) 增大单调递减,代码里用 while() 处理。所以求和符号是怎么变化的呀。

发现后面是个整数分块的形式,但是又不大经典。

回顾一下整数分块都是怎么做的?\(\forall x\le \sqrt n\) 直接枚举做,\(x>\sqrt n\) ,我们枚举结果 \(\lfloor\frac{n}{k}\rfloor\) ,确定出 \(k\) 的范围 \([l,r]\)

此时满足条件的 \(k\) 的个数是好求的,经典容斥:l-r+1-P(l,r,2)-P(l,r,5)+P(l,r,10) 。其中 \(p(l,r,k)\) 表示区间 \([l,r]\) 有多少 \(k\) 的倍数,这一步可以差分得到。

复杂度 \(O(\sqrt n)\)

T2 考 考试

求第 \(k\) 个满足十进制的表示是其二进制表示后缀的数,\(k\le3000\)

例如 \((10)_{10}=(1010)_{2},(110)_{10}=(110,1110)_2\)

结论:\(10^k\) 的二进制结尾一定有且仅有 \(k\)\(0\) :证明:\(10^k=2^k\times5^k\)

所以,若 \(x\) 不满足条件,则 十进制 \(x\) 前加一个 \(1\) 仍然不满足条件。

于是,我们只需要对满足条件的十进制后缀,前面加上1或者0。

这个过程是用一个堆来实现的,初始放一个0,存三个参数:大小 \(val\) ,位数 \(l\),是否有前导0。

每次从堆中取出一个位数最小,位数相同值最小的,在他前面加1,0,检查是否还合法:

若在前面加1:如果加上10^k后,二进制上那一位(k+1) 还是1,则说明合法

若在前面加前导0,本质上相当于只能保证二进制前 \(k\) 位不变,第 \(k+1\) 位如果变成1的话,就和加0不符,所以判断 \(x\)\(k+1\) 位是否为0 。

如果一个数没有前导0,cnt++直到k。

但是这样在k=2000就爆int128了,恶毒的出题人还让我们写一个只包含01的高精度。

Nfls 9.28

T1 倍数区间

定义一个区间是好的,当且仅当存在一个数是这个区间内所有数的因数,求最长合法区间长度和所有最长合法区间的左端点。

$O(n\log^2) $ 是容易想到的,\(ST\) 表维护 \(gcd\) ,二分序列长度即可。

又因为 \(ST\) 维护的 \(gcd\) ,线段树也可以做,所以线段树二分,对于每个位置 \(i\) ,在线段树上找到这个叶子,往上跳再往下跳吗。不会、

T2 飞翔的鸟

在玩飞翔的小鸟

每次可以从 \((x,y)\to (x+1,y),(x+1,y-1),(x+1,y+1)\) ,且 \(y\in [1,k]\)

有一个位置有障碍,覆盖了 \(y\in [1,a] ,[b,k]\) 的位置。

要想从 \((1,\frac{k}{2})\) 飞到 \((n,\frac{k}{2})\) ,障碍物在 \([2,n-1]\) 的某一个位置随机出现。

求期望可行的飞行路径数量。 \(n\le10^9,k\le130\)

考虑 \(dp\) ,因为 \(k\) 很小,考虑构造矩阵转移。

\(Ans=\sum _{i=2}^{n-1} A^{i-1}\times B\times A^{n-i}\)

Bct 9.30

T1

躲避滚石

参考系变换,相当于滚石不动,人在动。

注意瞬时移动和单位时间移动的区别

T2 小木棍

两部分截出的价值相等的点是好计算的,这些点是关键点,关键点之间的长度都有贡献。

T3 教室分组

将集合 \(a\) 分为若干组,使每组人数均为奇数,且人数在 \([l,r]\) 范围内。

定义一组的价值是这组的中位数,一个分组方案的价值是所有组价值的平均数。你要求分组方案价值最大。

\(n\le10^6,a_i\le2^{30}\)

首先排序肯定是要做的。

我们把每一组中位数称为 \(B\) ,小于和大于中位数的部分称为 \(A\)\(C\) 。发现最优方案中,最小的 \(B\) 一定大于最大的 \(A\) ,否则一定可以通过交换两者而使得方案数不变的情况下更优。

我们希望 \(B\) 尽可能都在数组后部,于是我们枚举最小的 \(B\) 的位置,只需检查

Sdfz 10.8

T2

\(n\) 个人有坐标 \(x_i\) 和影响力 \(e_i\) ,当你对 \(i\) 赠送一本书时,所有满足 $ {x_i-x_j}\le e_i-e_j$ 的 \(j\) 都会买这本书,求最少送多少书,可以让所有人都有书。

绝对值先拆式子,有:

\(x_j-e_j \ge x_i-e_i (x_i\ge x_j)\)

\(x_j+e_j\le x_i+e_i(x_i\le x_j)\)

不看括号内条件的话,带绝对值的式子和下面两条是完全等价的,也就是说:如果一个 \(j\) 同时满足上述两条,那么其一定满足原条件。

可以转换成线段覆盖问题,对于一个 \(i\) ,左端点为 \(x_i-e_i\) ,右端点为 \(x_i+e_i\) ,如果另一个 \(j\) 的线段被 \(i\) 完全覆盖,那么 \(i\) 就能影响到 \(j\) ,于是只需求出最少需要多少线段可以使所有线段被覆盖。排序后贪心选。

也可以以 \(x_i-e_i\)\(X\) 轴,另一个为 \(Y\) 轴,相当于能够影响所有 比 \(X_i\) 大,比 \(Y_i\) 小的,也就是点右下方的一个矩形,相当于一个二维数点,按 \(Y\) 轴排序后,从上往下枚举,如果这个点在之前已经被影响到了就不选,否则就选。

T4 [P5852 Bessie's Snow Cow P]

给定一棵树,点有颜色(可以叠加)。两种操作:

  1. \(x\) 整个子树增加一种颜色 \(k\)
  2. 查询 \(x\) 整个子树,每个节点的颜色数量之和。注意不是整个子树的颜色数。

\(n,k\le 10^5\)

我们开 \(k\)std::set 维护颜色为 \(i\)不交节点区间 ,换句话说,存下的是若干棵不交的子树的根节点。体现在操作中的就是每次加入点 \(u\) ,要删除 set\(u\) 子树的所有点。注意每个点只会被加入一次删除一次,所以复杂度是 \(O(n\log n)\)

对于查询的操作,我们仍用线段树,记 \(t_u\)\(u\) 的不同颜色个数,查询就是子树和。

对于修改的操作,如果 set 里已经有其祖先了,直接跳过不管;否则,我们删除 set 内一个点时,要将其贡献清除,也就是这个子树区间减一。最后加入 \(u\) ,整个子树区间加一。

代码难点在 set 遍历上:

找祖先:如果存在祖先,一定是 当前 \(u\) 的前一个点(以 dfn 为键),否则如果前一个不是祖先,那么就没有祖先,

注意 set 的边界问题:指针加减前后要判断和 begin()end() 是否相等。

set.erase 后寻址不连续,所以必须用 lower_bound 找到下一个点。 )

nfls 10.9

T1 华灵

构造

你被要求构造一个 \(n*m\) 的矩阵,你可以在每个位置填一个左括号或者右括号,求最多合法括号序列的行和列是多少。你需要输出方案。

构造题,完全猜错,在小数据下是对的,和指数暴力也拍了,屁用没有。

赛时的结论是 \(n+\frac{m}{4}\) ,但实际上考虑一个大于6的就可以想到,最优的方案数是 \(n+m-4\)

怎么构造呢?第一列,第一行,最后一行,最后一列都不合法,而且均全部是左括号和右括号,你发现中间是全部合法的。

但是这是在 \(n,m\) 较大的情况,若较小的情况,例如 2 和 2,考虑牺牲一半的行和列:答案为 \(n+m/2-1\)

()
()

T2 最近公共祖先

均摊分析

一棵有根树,点有点权,初始全部为白色,你有两种操作:

  1. \(u\) 修改为黑色
  2. 给定一个 \(u\) ,查询 \(lca(u,v)\) 的点权最大值,且 \(v\) 是黑色点。

暴力比较好做,dfs建出序后,每次修改后,相当于 \(1\)\(u\) 这条路径上的点都可以作为 \(lca\) 有贡献。

具体的,每次首先将 \(u\) 的子树全部和 \(w_u\)\(\max\),不断跳父亲,直到 \(1\) ,每次将除了上一步的子树以外的其它子树,和当前根 \(x\)\(\max\) ,记录一个 \(las\) ,每次修改两段即可,而每次询问子树查询即可。线段树维护单点查询,区间取 \(max\) 。甚至不需要 \(tag\) (或者称为 标记永久化)即可。这样复杂度是 $O(qn^2\log) $ 的。

但是这样其实很多是没有必要的,如果在向上跳的过程中,如果一个点已经被被访问了,那它至多有一个子树没有被更新,而它的祖先,一直到根,已经访问过了,再来一遍是完全等价的,都会修改除了当前子树的其他子树,所以我们用一个 \(vis\) 记录一个点是否被访问,一个点最多被修改两遍子树,均摊复杂度是 \(O(q\log n)\) 的。

nfls 10.10

T2 完全背包问题(同余最短路)

\(n\le 50\) 件物品有体积 \(w_i\le 10^4\) ,另给两个参数 \(L,c\) ,表示体积超过 \(L\) 的物品总共最多选 \(c\)\(m\le50\) 次询问,给定一个背包容量 \(W\le 10^{18}\) ,询问能否恰好填满背包。

首先排序把 \(w_i\) 分为两部分。令 \(dp_{i,j}\) 表示选 \(i\) 件超过 \(L\) 的物品,体积 \(\bmod w_0=j\) ,所需要的 最少 体积。

对于小于 \(L\) 的部分,跑一遍同余最短路即可把 \(dp_0\) 处理完。具体的,枚举每个物体 \(i\ge1\) ,枚举 \(j \in[0,w_0-1]\) ,每次从 \(j\) 建一条 \((j+w_i)\bmod w_0\) 的有向边,边权为 \(w_i\) ,跑最短路,实际是为了处理有后效性的dp问题。这样得到的最短路 \(d_i\)\(dp_{0,i}\) 的含义是相同的。

对于大于 \(L\) 的部分,因为范围小,所以直接大力 \(dp\) ,填表不好做,考虑刷表法,有:

\[dp_{i,j}\to \max (dp_{i+1,(j+w_k)\bmod w_0},dp_{i,j}+w_k) \]

最后统计答案,只需保证 \(\exist \ dp_{i,W\bmod w_0} \le W\) 即可,含义就是你可以加若干次 \(a_0\) 达到 \(W\) ,但是不能现在已经超过 \(W\)

T3 ydc的大树 (CF348E Pilgrims)

简化题意

给定一棵已经确定黑白染色的树,边有边权,其中有 \(m\) 个黑点,其它都是白点。

对于一个黑点,我们定义他的好朋友是离他最远的黑点。显然,一个黑点可能有多个好朋友。

现在要删除一个白点,使得删除后,不能到达任意一个好朋友的黑点数量尽可能多,求出这个数量的最大值,以及多少个白点删掉后满足这个最大值。

看到最远点想到树的直径两端点,但是显然此时的树并非原树,我们只会用到黑点,因此求直径时,实际上这棵树是只有黑点的虚树。我们两遍 dfs 跑出树的直径 \(len\)

树的直径的长度是抽象的,但是直径两端点却是不唯一的,一个trick是树的直径的中点是唯一的(NOIP2007 树网的核),注意这里的中点是 离 \(\frac{len}{2}\) 最近的点,如果是两个点则任取一个。这里的中点有可能是白点。

找到中点后,我们把中点提拉成根,变成一棵有根树,此时任何一个黑点想要到达他的好朋友,一定要经过根。

然后我们枚举要删除的白点 \(u\) ,白点子树的所有黑点肯定都算入答案,另外我们要分类讨论。其依据是,整个树的直径,要么是一条从根往下延伸的最长链和另一条次长链,要么是两条最长链。(实际情况可能是若干条)

  1. 这棵树由一条最长链和若干次长链组成,且 \(u\) 在最长链上:

    此时,这条最长链上的,非 \(u\) 子树的黑点,仍然可以到达他们的好朋友,即次长链的最深黑点。而除了他们,其他黑点都到达不了他们的好朋友,即最长链的最深黑点。

  2. 这棵树由一条最长链和若干次长链组成,且 \(u\) 在次长链上:

    此时,这条次长链上的,非 \(u\) 子树的黑点,仍然可以到达他们的好朋友,即最长链的最深黑点。但是,唯一的最长链上的黑点都到达不了他们的好朋友,即次长链的最深黑点。

  3. 这棵树由且仅由两条最长链组成,且 \(u\) 在最长链上:

    此时, \(u\) 这条最长链上的,非 \(u\) 子树的黑点,仍然可以到达他们的好朋友,即另一条最长链的最深黑点。但是,另一条最长链的所有点都到达不了他们的好朋友,即 \(u\) 这条最长链的最深黑点。

    当然,如果有多条最长链则不会出现此情况。

对于上述信息,笔者的处理方式是若干遍 dfs 分别处理出 在以直径中点为根的树中,\(dp_i\) 表示 \(i\) 子树的最深黑点的深度,\(anc_i\) 表示 \(i\) 的祖先是根的哪个儿子,最长链的数量 \(cnt\)。这样如果 \(dp_u=dp_{root}\) ,则说明 \(u\) 在最长链;若 \(dp_u+dp_{root}=len\) 则说明 \(u\) 在次长链。

[评测记录](Submission #227608771 - Codeforces)

nfls 10.12

T1 yxh 与数组

给定四个数 \(a,b,c,d\) 判断 \(a\)\(b\) 的乘积是否是 \(c\)\(d\) 的乘积的因数, \(10^7\)

显然是存不下的,而且模意义下没有整除的性质。

注意到 \(a\)\(b\) 的因数的充要条件是 \(a,b\) 质因数分解后 \(a\) 每个质因数的指数都小于等于 \(b\) 的。

我们发现 \(1e7\) 内素数个数只有 \(6e5\) 个,枚举每个质数,检查其在区间 \([l,r]\) 对指数的贡献。可以差分+类似容斥但不需容斥做。

我们还要枚举每个质数的若干次幂,这样总复杂度是 \(O(n\log n)\)

T2 谦逊

给定 \(n,k\le 10^{15}\) ,两种操作。

  • \(n=n+k\)
  • \(n\) 变为其十进制表示下,各数位之和。

\(n\) 最小能变成多少,并求出变成最小值,所需的最少操作数。

对于十进制表示下各数位之和的定理:

\[(9999+1)a+(999+1)b+(99+1)c+(9+1)d+e =a+b+c+d+e\mod 9 \]

类似小学数学的 快速判断一个数是不是 \(3\) 或者 \(9\) 的倍数。

于是我们确定答案一定在 \([1,9]\) 内,而且粗略估计 \(1e15\) 的数,只需做 \(3\) 次操作2 变成个位数。

但是中间会穿插若干个操作1,注意到 只有 \(n+k,n+2k,...n+8k\) 是有意义的,因为在模9意义下循环。

所以总操作不会超过13次,直接暴力 dfs 即可。

T3 基础fake 练习题

给定一棵树,点有点权 \(c_i\),给定 \(m\) 种覆盖方案 \(u_i\to v_i\) ,每一个点上的覆盖次数不能超过 \(c_i\) ,求最多可以使用多少覆盖方案。

考虑 贪心,不妨令 dep[u]<dep[v] 我们肯定优先选择那些 \(u\) 尽可能深,且 \(v\) 尽可能浅的方案。

用线段树暴力树剖即可。

Nfls 10.13

T1 橙子

给定 \(n\) 个数 \(a_i\) ,若干次询问,每次询问 \([l,r]\) 的区间子区间,异或和的异或和。

异或满足结合律和交换律,只需判断每个 \(a_i\) 在这一串出现次数的奇偶性。对于一个 \(a_i\) ,在该区间内,左边有 \(i-l\) 个数,右边有 \(r-i\) 个数,出现次数就是 \((i-l)(r-i)\) ,当长度为偶数时,左右至少有一个是偶数,总结果就是偶数,否则,当 \(i\) 为奇数时是结果是奇数,为偶数时结果是偶数,或者反之。用两个树状数组维护奇数位和偶数位就可以。

T2 椰子

给定 \(n\) 个椰子的硬度 \(a_i\) ,一次操作可以让一个椰子硬度减一,但是这些椰子的顺序是不知道的,求打碎 \(m\) 个椰子至少需要多少操作。\(n,m\le5000\)

这个题相当于有神秘力量不断地将最硬的椰子给我们敲,我们永远会得到最坏情况。

结论:敲掉任意一个硬度为 \(x\) 的椰子,所有硬度 \(>x\) 的椰子都至少被砸了 \(x\) 次。

考虑反证法,如果一个硬度 \(>x\) 的椰子敲了少于 \(x\) 次,但是一个硬度等于 \(x\) 的椰子被砸碎了,神秘力量肯定不会让我们这样做。而是会给我们那个硬度大的椰子砸,而导致这个椰子并没有碎,这是牠想看到的。

因此我们的策略大概是,(先从大到小排序后)选择一个基准 \(h_i\) ,一直敲,如果椰子没有碎就换下一个椰子,如果碎了,将 \(h\) 降低。

于是 DP 是正确的,设 \(dp_{i}\) 表示对于前 \(i\) 个椰子,敲碎了 \(j\) 个,最少砸多少次,转移则是枚举当前选择的基准 \(a_i\) ,敲了多少个椰子(一个后缀),转移有 $dp_{i,j}=\min {dp_{k,j-1}+a_i \times (i-k) } $

暴力是 \(O(n^2m)\) 的,不难发现可以斜率优化,复习一下:用 \(b\) 表示只与 \(i\) 有关的,用 \(kx\) 表示两者都有关的,用 \(y\) 表示只与 \(j\) 有关的。

\[dp_{i,j}=dp_{k,j-1}+a_i\times i- a_i \times k \\ 令 k'=a_i,x=k,b=dp_{i,j}-a_i\times i;\ y=dp_{k,j-1} \\ b=y-kx \\ y=kx+b \\ \Longleftrightarrow \]

分析单调性: \(x\) 单调递增。

因为取 \(b\) 的最小值,且 \(k\) 为正数,故维护一个 \((i,dp_i)\) 的下凸包。可以用单调队列优化。

T3 【IOI】Wall

维护一种数据结构,支持区间取 \(\max,\min\) ,最后输出每个位置的值。

显然线段树,我们甚至不需要维护信息。

考虑两种标记 \(max\)\(min\) ,注意到标记显然有先后顺序,但是当前节点受到一个新标记后,就把老标记重置为新标记。例如:原本节点上有一个 \(min=5\) ,此时下传一个 \(max=7\) ,则更新 \(min=7\) ;此时下传一个 \(max=3\) ,则无需更新 \(min\) 。若此时下传一个 \(min=3\) ,则更新 \(min=3\) ,若下传 \(min=7\) ,则不用更新 \(min\)

T4 控制

\(n\) 类装备,每种类型有 \(m_i\) 种,且各有一个魔力值,定义一个方案为每一类选一个;你要求出前 \(k\) 大方案的魔力值总和。

套路题,优秀的暴力是 用优先队列维护,类似搜索,从一个状态向外转移,并加入堆里。为了避免加重,需要加入顺序的约定。

正解比较复杂,但发现本质和 \(dij\) 很像,所以可以转换成图论,建立 \(nm\) 个点,每个第 \(i\) 类的点,向每个第 \(i+1\) 类的点连边。直接可并堆优化 k 短路即可。需要虚拟源点和汇点。

Nfls 10.14

T1 超速

出题人没码,二分答案题少打了一句话:最大值最小。

T2

给定序列 \(a_i\) ,定义一段区间的价值是这段区间不同数的个数,定义 \(S_i\) 为整个序列所有长度为 \(i\) 的区间价值的和。

你要求出每个 \(S_i\)\(n\le1e5\)

\(pre_i\)\(a_i\) 上一个出现的位置, \(nxt_i\)\(a_i\) 下一个出现的位置。

考虑贡献,\(a_i\) 作为这个区间第一个出现的,枚举 \(i\) 左边选了 $[0,i-pre_i+1] $ 个,右边选了 \([0,n-i+1]\) 个,记两边选择之和为 \(sum\)\(a_i\)\(S_{sum}\) 有 贡献 。若 \(sum\le \min(i-pre_i+1,n-i+1)\times 2\) ,是一个区间加等差数列的形式,其中首项为1,公差为1。否则,对于 \(sum\in [\min(i-pre_i+1,n-i+1)\times 2,\min(i-pre_i+1,n-i+1)+\max(i-pre_i+1,n-i+1)]\),也就是一边会多出来的部分,是区间加常数。

区间加等差数列(一次函数)怎么做?等差数列本质是差分数组的区间修改,于是我们可以差分 差分数组做到 \(O(n)\) ,也可以套一个线段树支持区间修改,区间前缀和 ,复杂度 $O(n \log n) $。毕竟询问是最后一块询问,选择哪一种方法都可以通过本题。复杂度瓶颈在 map 记录 pre

讲一下二维差分是怎么做的。

上面说的有点麻烦了,实际上代码很简单。

for (int i = 1; i <= n; i++) {
       int A;
        cin >> A;
        int x = i - p[A];
        int y = n - i + 1;
        if (x > y)
            swap(x, y);
        sum[1]++, sum[x + 1]--, sum[y + 1]--, sum[x + y + 1]++;
        p[A] = i;
    }
    for (int i = 1; i <= n; i++) sum[i] += sum[i - 1];
    for (int i = 1; i <= n; i++) sum[i] += sum[i - 1];
    for (int i = 1; i <= n; i++) cout << sum[i] << " ";

T3 ROIR 海报

\(n\) 个人围成一圈,每个人有一个美观值 \(w_i\) ,你要选出其中若干个人,不能选择连续超过 \(4\) 个人。使得美观值最大。

同时有 \(q\) 次修改某个人的 \(w_i\) ,你需要对每次修改后询问最大美观值。

序列上的【动态dp】 板子题。用广义矩阵乘法和线段树来维护带修改的 dp 方程。 \(dp_{i,j}\) 表示以 \(i\) 结尾,最后选了 \(j\) 个人的最大美观值。

无修改时,方程比较简单: $dp_{i,0}=\max {j=0,1,2,3} dp $ ;\(dp_{i,j}=dp_{i-1,j-1}+a_i,j\in[1,3]\)

因为是环,终点和起点也要满足不能连续超过4个人,比较无脑的方式是断环成链,不同起点要跑四遍线段树。但是下文对此情况有巧妙的避免方式。

对于带 $\max $ 的方程,我们一般需要广义矩阵乘法 \(A*B=C\) ,其中 \(C_{i,j}= \max_{k=1} (A_{i,k}+B_{k,j})\)

至于这样做的可行性,关键在于矩阵乘法仍然满足结合律和分配率,即内层运算对外层有分配率。回顾普通矩阵乘法,加法对乘法有分配率;广义矩阵乘法中,max+ 也有分配率。即 max(a,b)+c=max(a+c,b+c)

将转移方程写成矩阵的形式:

\[\begin{bmatrix}dp_{i-1,0}& dp_{i-1,1}& dp_{i-1,2} & dp_{i-1,3} \end{bmatrix} \times \ \begin{bmatrix} 0 & a_i & -\infty & \infty \\ 0 & -\infty & a_i &-\infty \\ 0 & -\infty & -\infty &a_i \\ 0 & -\infty & -\infty &-\infty \end{bmatrix} =\begin{bmatrix}dp_{i,0}& dp_{i,1}& dp_{i,2} & dp_{i,3} \end{bmatrix} \]

又因为有结合律,所以

\[A \times B_1 \times B_2...\times B_n= A\times (\prod B_i) \]

因为带修改,用线段树维护 \(\prod B_i\) ,每次修改都是一次线段树单点修改矩阵,每次询问直接用根节点即可。

如何避免建四棵线段树呢?因为是个环,所以初始矩阵 \(A\)\(dp_{0,j}\) 就是答案矩阵中的 \(dp_{n,j}\) 。我们直接讨论以 \(n\) 结尾选了 \(j\) 个,初始矩阵除了 \(dp_{0,j}=0\) ,其他都是 \(-\infty\) ,此时答案矩阵只能选 \(dp_{n,j}\) 。而对应在中间的转移矩阵,就是第 \(j\) 行,第 \(j\) 列的元素。所以在代码实现中,不需要维护初始矩阵和答案矩阵,最后只需统计线段树根节点矩阵对角线的最值即可。

代码实现上有一些技巧,例如可以通过重载一维运算符而实现重载两维运算符,涉及内存访问的一些知识。注意开 long long

Luogu csp 模拟赛 10.15

T2

\[f_i=\sum_{j=0}^{i-1} f_j \times (s_i \oplus s_j) \newline s_i\oplus s_j 的第 k 位是 1\to f_j 对 f_i 有 2^k 的贡献。 \\ 枚举 s_i\oplus s_j第 k 位是 0 还是1,实际上是枚举 s_j 的第 k 位是什么,以及对应的 f_i 的和。再乘上一个 2^k 。 \\ 对于更新,判断 s_i 的第k位是什么,并放进桶里。 \]

Nfls 10.16

T1 魔力子串

给定一段字符串,设字符串中的不同字符数量为 \(k\) ,定义一个有魔法的子串,满足子串中不同的字符数为 \(k\) ,且每个字符的出现次数都相同。

csp预告题。

发现就是等价于 子串 内所有字符都有,且数量相同。肯定要用桶来统计,记 \(cnt_{c,i}\) 表示 字符 \(c\) 在前 \(i\) 位出现了多少次,一个子串合法,等价于 $\forall c,cnt_{c,r}-cnt_{c,l},= cnt_{c',r}-cnt_{c',l} $ 。(先考虑只有两种字符的情况)这样等号一侧不好处理,我们移项可以得到: \(cnt_{c,r}-cnt_{c',r}=cnt_{c,l}-cnt_{c',l}\) 。 (对于更多字符的情况)这样我们每个位置有一个长度为 \(\sum\) 的数组,对于字符串子串数量问题很容易转换成这样,然后哈希+ map 处理。 ——csp-s2023T2

另外值得一提的是,vector 自带比较符,但是比较是线性的哦,不过这道题 vector 长度只有 26

在 u群里学到了用线段树维护 hash\(O(\log)\) 复杂度方法。感觉可以一学。

T2 吃树

​ 给定一棵树,求将其分为任意多个大小相同的连通块,有多少种分法。 \(n\le1e6\)

猜结论题。

如果每个块大小都是 \(2\) ,那么一棵有两个儿子,三个节点的子树显然是非法的。

整棵树能分成大小为 \(x\) 的连通块,首先需要 \(x\mid n\) 。其次你要有 \(\frac{n}{x}\) 棵子树的大小要是 \(x\) 的倍数。

所以枚举 \(n\) 的因数,\(O(n)\) 检查,复杂度 \(O(d(n)\times n)\)\(d(10^6)\) 大约为 \(240\)

T3 弹弹床

\(n\) 个弹弹床,每个有属性 \(c=L\)\(R\) ,代表其下一步能跳到所有在左边/右边的弹弹床,问从任意一个点开始游戏,有多少种方案,能够跳 \(n\) 张床恰好一次,且 最后一步停在 \(i\)\(n\le5000\)

神仙dp题。将路径拆成子路径而便于转移

一档部分分是 \(c_n=R\) ,考虑这个怎么做?

意思就是弹到 \(n\) 后再也出不去了,所以有且仅有 \(i=n\) 时有答案,其它都是 \(0\)

分析一下弹到 \(n\) 的过程,最后一步一定是向右到 \(n\) ,中间会向右,向左,(我们把相邻两个向右操作看作一次向右),更进一步,我们可以化简一次操作为:(向左)+向右,即可能没有向左,但最后一定向右。

例如 RRLRLR 路径可以为 \(4\to 5\to2\to3\to1\to6\) 可以拆成 \(4\)\(5\to 2\)\(3\to 1\to 6\) 三条子路径。

考虑 \(dp\),设 \(dp_{i,j}\) 表示前 \(i\) 个点,形成了 \(j\) 条最后向右的子路径 的方案数。

然后我们从左向右枚举,遇到一个 \(c_i=R\) ,则可以作为新的一条路径的开头,也可以作为之前的一条路径的结尾,如果遇到一个 \(c_i=L\) ,则可以作为之前的一条路径的开头,也可以合并两个路径

转移:

\[dp_{i,j}=dp_{i-1,j-1}+dp_{i,j}\times j \newline dp_{i,j}=dp_{i,j}\times j+dp_{i,j+1}\times j\times (j-1) \]

最后答案即 \(f_{n,1}\)

对于一般的情况

还是用 路径合并 的思想,我们求出最后一步向右的 \(f_{i,j}\) 和最后一步向左的 \(g_{i,j}\) 。对于当前点 \(i\) 的答案路径,一定是 左边最后一步指向右,右边最后一步指向左,如此循环。我们只需考虑答案怎么拼接。无非 LRL,RLR,LRLR,RLRL , 这样四种情况。

  • LRL \(f_{i-1,j} \times g_{i+1,j+1}\times j\ ! \times (j-1)\ !\)
  • RLR \(f_{i-1,j+1} \times g_{i+1,j} \times j\ ! \times (j-1) \ !\)
  • LRLR+RLRL\(f_{i-1,j}\times g_{i+1,j} \times j\ ! ^2\times 2\)

Nfls 10.17

T1 子段排序

给定两个数组 \(a_i\)\(b_i\) 。你可以进行若干次操作,每次选择 \(a\) 中任意一段 \([l,r]\) ,并排序,问是否能将 \(a\) 变成 \(b\) ,如果能,需要构造一组操作序列。要求操作数不超过 \(n^2\)

如果非法,的条件是什么? (CF1187D) :即 \(b\) 中出现 \(a\) 没有出现的逆序对。如果合法,一次排序至少减少一个逆序对,而逆序对的个数是 \(n^2\) 的。我们可以采用最暴力的方法,即冒泡排序:每次交换相邻两个。不断冒泡,直到两个全部相等。

T2 伪快速排序

你要执行如下的快速排序。

int partition(int l, int r){//这部分和快排相同
int x = a[r];
int i = l;
for(int j=l;j<r;j++){
  if(a[j] < x){
  swap(a[i], a[j]);
  ++i;
   }
}
swap(a[i], a[r]);
return i;
}
void Qsort(int l, int r, int h){
if(l<r && h>1){
  int m = partition(l,r);
  Qsort(l,m-1,h-1);
  Qsort(m+1,r,h-1);
}   
}

你想知道有多少个排列 \(a_i\) 满足在给定 \(k\) 的情况下,能变成有序数组。

快排的基本思想就是每次钦定一个标准,把小于标准的都扔前面,大于标准的都扔后面,递归实现。

但是 正常的快排,递归的深度是 \(\log\) 层,怎么考虑在 \(k\) 层递归。

\(k=2\) 时,只进行一次,需要 \(a_i<a_n\) 的部分在原序列是有序的,\(a_i>a_n\) 的部分在原序列也是有序的。枚举 \(a_n=i\) ,就是把 \([1,i-1]\) 的有序排列和 \(i+1,n\) 的正序排列插空变成一个。也就是说,一次 partition 的本质是将两个有序数组合并成一个有序数组,否则仍然是无序数组,返回的是 \(<a_n\) 的个数。

排列方案考虑 dp ,设 \(dp_{i,j}\) 表示长度为 \(i\) ,进行 \(j\) 次递归后,数组有序的方案。

枚举 小于 \(a_n\) 的个数 \(k\) ,则有转移:

\[dp_{i,j}=\sum_{k=0}^{i-1} \binom{i-1}{k} dp_{k,j-1} \times dp_{i-k+1,j-1} \]

组合数的意义是 选择 \(k-1\) 个数放在前面作为一个有序数列。

T3 二进制式

给定一个二进制表示串,例如 ((x^x)|(x&x)) ,其中包含 \(n\) 个变量 \(x_i\) ,对于每一个 \(x_i\) ,你要输出:当除 \(x\) 外其他 \(n-1\) 个变量固定时,\(x\)\(0\)\(1\) ,最终表达式的值不同的概率。 \(n\le10^5\)

例如 x or y :固定 \(y=1\) 的情况下,\(x=0\)\(1\) 没有区别,固定 \(y=0\) 的情况下,\(x=0\)\(0\) ,否则是 \(1\) 。所以概率是 \(\frac{1}{2}\)

这种确定总数:\(2^{n-1}\) 的概率问题,直接统计 分子即可。带着分母求就又是逆元又是什么,非常难算。

首先我们不难将这个字符串通过 栈 维护出一棵前缀表达式二叉树。其中 非叶子节点都是 符号,叶子节点是 \(x\) 。但是注意 字符串的大小是 \(n\)\(4\) 倍以上。(挂40)

接下来肯定是要树上 \(dp\)\(n^2\) 的暴力做法就是每次固定一个数,然后做一遍 dp\(f_{u,0/1}\) 表示 \(u\) 节点答案为 \(0/1\) 的方案数。

例如:当 op='^' 时,\(f_{u,0}=f_{ls,1}\times f_{rs,0}+f_{rs,1}\times f_{ls,0}\)

考虑正解:对于一次修改,影响到的点就是从 \(u\)\(1\) 这条链上。于是我们再开一个 \(g_{u}\) 表示 \(u\) 子树内有固定,整个子树外,使得答案不同的方案数 。

这里跳出常规 $dp $ 模式了

\(g_{ls}=g_u\times f_{rs,x}\) 其中 \(x\) 在符号不同时不同。例如 或运算:需要 \(f_{rs,0}\) 。因为原本不同 或 0 还是不同,原本不同 或 1 就都相同了。

答案即 $g_i $ 。

Nfls 10.18

T1 玛雅历

日期型大模拟,可以采用公元前暴力做,公元后,400年的周期直接统计,剩下的散块暴力做。

T2 大融合

简化并省略简单部分:

给定一个 \(n*n\) 的棋盘,点有分数值和颜色,如果上一步和当前颜色相同,额外获得 \(1\) 分,你可以设置 \(g\) ,跳跃距离为 \([max(1,d-g),d+g]\) ,只能往下往右。求获得 \(s\) 分数的最小 \(g\)

外层直接二分,怎么用单调队列优化这个东西。

对于二维上的问题,我们只需要每一行,每一列,都维护一个单调队列即可,两者之间取 \(max\)

对于有颜色的问题,因为这道题颜色数比较少,可以每一行,每一列 的每一种颜色建单调队列。如果颜色多了,一个套路是把颜色都扔进 set 里,即每一行,每一列,开 \(n+m\)setset 里的元素是单调队列。找到时间空间的平衡。

T3 好 ♂ 朋 ♂ 友

给定一个序列 \(a_i\) ,和集合 \(S\) ,并有若干次询问 \([l,r]\) ,每次询问区间内有多少子区间,满足子区间的或和,的个位数为 \(s \in S\)

经典套路题,离线后固定左端点,只有 \(O(\log W)\) 个关键点会影响,快速找出这些点。只需要找 \(a_l\) 的二进制表示中,为 \(0\) 的位上,后面第一个该位为 \(1\) 的位置。二进制拆位后可以二分。

得到这些 关键点后,直接暴力找出 满足 的位置区间,例如 $[key_i,key_{i+1}-1] $ ,然后对这些区间+1。如果我们倒序枚举询问,即从右往左加,那么当前 \([l,r]\) 的询问就是 该区间的区间和。好神奇。不用写区间历史和了。还是说根本不是一回事呀。

胜利一中SD联测2 10.18

T1 谁共一杯方酒

给定 \(n\) 个区间,求最多多少个区间满足 \(\forall\ i\)\(i+1\) 包含。

按右端点排序后,等价于左端点的最长上升子序列。

线段树大常数选手+dwt没开O2 \(\to\) \(90 pts\)

T2 约会

给定一棵树,边有方向且有边权,你可以通过 \(1\) 的代价改变某个点的方向,你需要选择一个点 \(x\),使得最远的点到 \(x\) 的距离不超过 \(D\) ,且满足代价最小。求代价。

最远的点可以用树的直径求,距离直接带 \(\log\) 差分。

代价稍微推一下,等价于:子树内的下边+ \(1\)\(x\) 链上的上边+除两者外的下边。

T3 乱杀

有两个人在数轴上,给定若干个限制:需要在 \(t_i\) 时刻至少有一个人在 \(x_i\) 位置上,求两个人的最大速度最小是多少。

  • 考虑 \(n^2\) \(dp\) 做法:

    和 bct暑假集训某一天的 \(T4\) 非常像,关键在于 两个人的位置,其中一个人一定在 \(x_i\) 上,那道题我们 \(dp\) 另一维存另一个人的位置,这里有些难办了,因为位置可能是实数,所以我们可以存 另一个人上次击球的时刻,位置即 \(x_j\) ,因为我们知道 一个人两次击球之间是会往返的。这样存就一定是整数了。转移依旧是经典的 \(n*O(1)+O(n)*1\) 的形式。

  • \(n \log n\) 二分答案:

    与那一题不同的是,\(dp\) 式子是中有若干 \(\min 和 \max\) ,数据结构难以维护。考虑二分答案。(和 \(dp\) 已经完全没关系了)

    赛时也想到了,我们知道其中一个人 \(P\) 的位置 \(a_i\) ,另一个人 \(Q\) 的位置一定是一个区间的的形式,设该区间为 \([L,R]\) ,二分答案速度为 \(V\) ,在 \(\Delta T\) 的时间内最多可以走 \(S=V\Delta T\) 的路程。则 \(P\) 下一步可以走到 \([a_i-S,a_i+S]\)\(Q\) 下一步 可以走到 \([L-S,R+S]\)

    • 如果这两个区间都到不了 \(a_{i+1}\) ,那么说明无解。

    • 如果 \(P\) 能够到达,\(Q\) 不能到达。那么 \(P\) 下一步去找 \(a_{i+1}\)\(Q\) 下一步的区间再各左右扩展 \(\Delta S\)

    • 如果 \(Q\) 能到达, \(P\) 不能到达,两者身份互换。

    • 如果两者都能到达,那么 \(L\)\(R\) 的取值对上述情况取最值即可。

      为什么是对的?此时另一个人处于两个人的叠加态,进行下一步时,我们实际会用到谁,那个人就是谁,因为两者都可以用,而且我们不关心他们到底是谁。

      感觉是有点神仙的贪心。

    [评测记录](记录详情 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn))

T4 红藕香残

给定一个序列 \(a_i\) ,和常数 \(k\)。多次询问给定一个区间 \([l,r]\) ,删掉 \(k\) 个数后,区间 \(\gcd\) 最大是多少?注意 \(k\le3\)

  • 首先考虑 \(k=0\)st表

    但正解肯定很难从这上面想,注意到 \(\gcd\)\(|,\&\) 类似,固定左端点后只会变化 \(\log\) 次,因为每次变化至少除以二。因此我们还是找所谓关键点。

    那么我们从左到右枚举右端点。记二元组 \((l,v)\) 表示每个关键点的位置,以及每个关键点的一个后缀 \(\gcd\) ,即 \([l,r]\) 。初始只有 \((1,a_1)\)

    然后考虑右端点扩展,之前是关键点的有可能还是关键点,之前不是关键点的一定不会是新的关键点 。具体的,我们新加入一个关键点 \((r,a_r)\) ,然后更新关键点 (不超过 \(\log\) 个)的 \((l,v)=(l,\gcd(v,a_r))\) 。再对所有 \(v\) 相同的,只保留从右向左第一个即可。

    对于询问,我们直接找右端点为 \(r\) ,左端点最小的一个 \(l\)\(v\) 即可。复杂度 \(O(n\log n)\)

  • 考虑 \(k=1\) ,我们要删除一个数。可以肯定的是我们一定会删关键点,否则对答案是没有贡献的。于是枚举 以 \(r\) 为右端点的 \(\log\) 个关键点( \((r,a_r)\) 算作一种关键点,不需额外考虑)。枚举删的点后还要加上找左端点,然后求两者 \(\gcd\) 。复杂度 \(O(\log^2)\)

  • 对于 \(k>1\) 的情况,直接 暴力dfs枚举删点位置,暴力做就行,常数极小,1e5 \(O(n\log^4)\) 可以通过???

卡常题了属于是。

[不过调了大约2h,怎么回事呢?](记录详情 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)) 一开始我在 dfs 的时候是类似 dp 的, ans=max(ans,gcd(dfs(l,y-1,k-1),query(y+1,r))); 但实际上这肯定不满足dp,是直接把所有情况枚举出来统一处理。如下

void dfs(int l,int r,int R,int k,vector<int>v) {
    if(k==0) {
        int ll=l,sum=0;
        for(int i=v.size()-1;i>=0;i--) {
            int y=v[i];    
            sum=gcd(sum,query(ll,y-1));
            ll=y+1;    
        }
        sum=gcd(sum,query(ll,R));
        ans=max(ans,sum);
        return ;
    }
    vector<int>t=v;
    for(int i=s[r].size()-1;i>=0;i--) {
        int y=s[r][i].l;
        if(y<l) return ;
        t.push_back(y);
        dfs(l,y-1,R,k-1,t);
        t.pop_back();
    }
}

还有若干细节,例如我是用右端点,所以遍历 vector 都要倒序枚举。

CSP-S 2023

T1 [CSP-S 2023] 密码锁

简单模拟,不过大样例想了挺久。

T2 [CSP-S 2023] 消消乐

给定一个字符串,求有多少个子串满足可被消除。一个子串可被消除的定义是:任意两个相同的字符可以拼起来,然后消去,最后消完。

考前刚做过 hash 统计字符串的题,没想起来,寄。

\(n^2\) 暴力用栈维护即可,一个子串合法 当且仅当栈被消除至空 类似括号匹配。

根据栈的启发,一个常见的 trick 是将区间为 \(0\) 转换成前缀相等来统计。用 哈希维护一个栈,\(O(n)\) 求出一遍前缀 哈希栈。对于一个栈的状态,哈希值为 \(s\) ,用一个 map 维护之前有多少个 s 。答案累加 map[s] 即可。

如果我们不用 hash ,也可以考虑 dp\(dp_i\) 表示以 \(i\) 为右端点的答案,怎么转移? 使用 \(pre_i\) 转移比较困难,因为不能保证 \([pre_i+1,i-1]\) 是合法括号串。我们要想转移肯定是从第一个 位置 \(x\) 满足 \(x+1,i-1\) 是合法串,发现字符集较小,只有 \(26\) 。不妨记 \(g_{i,c}\) 表示 \(i\) 往前第一个位置 \(x\) ,满足 \(s_{x}=c\)\([x+1,i]\) 为合法串。转移就从 \(g_{i-1,s_i}\) 转移。更新 \(g_{i,c}\) :若 \(s_i=s_{i-1}\) ,则 $g_{i,s_{i-2}}=i-2 $ 。否则,记 \(t=g_{i-1,c}\) ,所有 \(g_{i,c}\) 都从 \(g_{t-1,c}\) 转移而来。

T4 种树

Nfls 10.23

T2 括号

给定若干次操作,每次往字符串的后面加入 \(c_i\) 个左括号或者右括号,问最终有多少合法括号序列。

回顾括号序列的经典套路,要么卡特兰数,要么看作区间dp,要么分别看作 +1-1 。对于在序列上且给定的问题,常常想第三种方法。

如果是 \(c_i=1\) 的情况,回顾一下:

也就是 \([l,r]\) 合法的充要条件是 \(cnt_{l-1}=cnt_r,\ \forall \ x,cnt_x\ge cnt_r\)

也就是一个很类似单调栈的东西,维护左端点,每次加入 \(cnt_r\) ,将所有大于 \(cnt_r\) 的都弹出,然后统计的就是 \(cnt_l=cnt_r\) 的贡献。时间复杂度 \(O(n*c_i)\)

推广到更一般的做法,我们维护一个栈存两种值:左括号连续段的长度,以及 拼成的合法括号串数量。这样一个右括号连续段过来消,把一串左括号消完,再加上这个数字,再消,再加。

T3 学校

\(a\) 有多少子序列 \(p\) 满足,\(p\) 中任意四个相邻元素的异或和不为 \(S\) 。其中 \(a_i\) 互不相同。

最朴素的 \(dp\) 是记录后三位分别是什么。\(O(n^4)\)

也就是 \(f(i,j,k)\to f(j,k,l)\) 。但是显然 我们可以算出来不合法的一些 \(i=S\oplus l.j.k\)

于是 \(f(*,j,k)-f(i,j,k)\to f(j,k,l)\) 。其中 \((*)\) 代表任何数。又因为 \(a_i\) 互异,所以可以做到 \(O(n^3)\) .

具体的,

\[f(i,j,k)=f(j,k,*)-f(j,k,x)\ 其中\ x=a_i\oplus a_j\oplus a_k\oplus S \\ 记 \ f(j,k,*)=g(j,k) \\ f(j,k,x)=g(k,x) 设此时从左往右的数分别为\ v,x,k,j,i\\ \because a_i\oplus a_j\oplus a_k \oplus a_x =S \and a_i \ne a_v \\ \therefore a_v\oplus a_j\oplus a_k\oplus a_x \ne S \\ \therefore f(j,k,x)=g(k,x) \\ \Longleftrightarrow g(i,j)=\sum_k g(j,k)-g(k,x) \ 状态数优化至 n^2 \\ 转移考虑开桶。每算完一个 g(j,k),贡献至 T_j 中。 \\ 每算完一个 g(k,x) ,贡献至 T'_{{a_k\oplus a_x}} \\ g(i,j)=T_j-T'_{a_i\oplus a_j \oplus S } \]

从四次方优化到平方,先优化转移,再缩减状态,再观察性质,最后优化转移。

Nfls 10.24

T2 K近查询

给定 \(n,m\) 。你需要对 \(\forall \ i\le n ,k \le m\) ,求出 \(i\) 前面 第 \(k\) 个 大于 \(a_i\) 的位置。(从后往前数) \(nk\le 10^7,k\le 5\)

T3 树上流水

给出一棵树,边有容量限制,\(1\) 号点作为根不断往外流水,1s 水只能移动一条边。求 使得所有叶子的水量 \(\ge k\) 的最短时间。\(n\le 1000,T\le 5\)

这样有先后顺序的树上问题一般是 贪心或者 \(dp\)

贪心解法

我们会尽可能希望 水先留到深度浅的叶子上,而且我们只会给这些叶子分配 它到根 路径上容量最小值,这么些水。

既然这样,我们将所有叶子按照深度排序,如果最小值非 \(0\) 的话,我们每次减去这条链的最小值,可以用树剖维护。最后,模拟一下叶子 接水的过程即可。总水量 \(\ge k\) 就跳出。复杂度 \(O(n \log^2 n)\)

dp解法

最主要的问题是不知道水往那边流,可以倒过来想,每个叶子都有水,问多久能让 \(1\) 的水量到达 \(k\) 。两者是等价的。

直接 \(n^2 \ dp\) ,设 \(dp_{u,j}\) 表示 $ u $ 号点在 \(j\) 时刻能有多少水。转移有 \(dp_{u,j}=\sum \min(dp_{v,j-1},w)\) 。可以暴力做,也可以 线段树合并加 Seg-beats。 复杂度少一个 \(\log\)

注意要开 long long

T4 逆序对

给定序列 \(a_i\) ,满足 \(n=2^k\)\(m\) 次询问,每次给出参数 \(p,l,r\) 。表示将 序列分成 \(2^p\) 段后,第 \(l\) 段到第 \(r\) 段,每段内部区间翻转,求操作后原序列有多少逆序对。 \(n\le 2^{20}\) 。 注意操作之间不相互独立。

一眼看上去就是自然的线段树结构,首先考虑 \(l=r\) 的情况:

将序列分块后,每次询问一个块,那么在线段树上一定能找到唯一的一段区间。我们需要给他打上一个翻转 \(tag\) ,意味着 他整个子树都需要不停交换左右儿子,直到叶子,这是标记对标记的下放。翻转这个节点,其逆序对数量变换为原先的正序对数量,这是标记对信息的影响。父节点逆序对数量等于左儿子逆序对数量,加右儿子逆序对数量,再加横跨中间,的逆序对数量(类似 cdq 分治),这是信息的合并。

建树过程可以和归并排序天然结合。维护区间逆序对 和 跨过中点的逆序对。

对于 \(l\ne r\) 的情况,问题可以转换成: 修改 $\log $ 个区间,查询 $\log $ 个区间。

Nfls 10.26

T2 树上删边

给定一棵树,点有点权,删一条边的代价是两边子树的权值最大值之和。求删完全部的最小代价。

每次贪心从最大点开始删。但是删边不好维护最大值。删边变成加边,从最小边开始加。并查集维护即可。

T3 欧几里得

定义 \(R(a,b)=R(\lfloor{\frac{a}{b}}\rfloor,b)\)\(T\) 次询问,每次给出 \(h,g\) 。构造一组 \(a,b\) 满足 \(R(a,b)=h,\gcd(a,b)=g\)

\(h,g\le 10^5\)

打表没啥规律,分析 \(R\) 的性质。

\(R(a,b)=h\) ,则一直递归到底层,有 \(R(h,1)=h\) ,同时, \(R(h,h+k)=h\) ,其中 \(k<h\) 。对于这种形式,可以继续套下去:即 \(R(h,h(h+k_1)+k_2)=h\) ;也就是说,\(b\) 可以写成 \(h(h(...+k_3)+k_2)+k_1\) ,就是一个 \(h\) 进制数的形式。

所以我们可以构造 \(r(h,b)=h\) 。只需满足 \(b\)\(h\) 进制表示下,最高位是 \(1\) ,因为初始是 \(1\) 。我们希望找到一个足够大的 \(b\) 满足 \(b\)\(g\) 的倍数。因为此时我们可以将 $r(h,b) $ 替换为 \(r(bh,b)\) ,此时 \(\gcd(bh,b)\)\(g\) 的倍数,但不一定等于 \(g\) 。考虑构造为 \(r(bh+g,b)\) ,要注意此时 \(g<b\) 。故要特判 \(b=g\) 的情况。此时 $\gcd(bh+g,b) $恰好为 \(g\)

因为 \(b=kg,bh=kgh,bh+g=kgh+g=g(kh+1)\)\(\gcd(g(kh+1),gk)=g\) ,因为 \(\gcd(kh+1,k)=0\) 。——相邻两个正整数互质。

所以构造方案有了,我们只需要找 \(b\) ,最高位是 \(1\) ,也就是 \(b=h^k+c\) ,且要满足 \(b\mod r=0\) ,因为 \(r\) 只有 \(1e5\) ,我们随便找一个比较大的 \(k\) ,使得 \(b>1e5\) ,然后再求出 \(c\) 即可 \(O(1)\) 做完。

T4 [没有上司的涨薪舞会

给定 \(n\) 个人组成的树形结构的关系网,有些员工要求涨薪资,有些员工则不想,现在他们去参加舞会,一个人选择去参加舞会,当且仅当:

  • 没有一个直接下属参加舞会,则 \(i\)\(p_i\) 的概率参加。
  • 否则不会选择参加。

每个员工可以选择给自己的所有下属加薪,\(u\) 能给 \(v\)\(a_u\) 的薪,当且仅当 \(u,v\) 全部到场,且 \(v\) 想要涨薪资。但是 \(a_u\) 有可能是负数,即降薪。

你需要分配每个人是想涨薪资还是 不想。求最大期望薪资是多少。

​ 根据期望的线性性,答案即为:

\[\sum_{i}\sum_{j\in anc_i} [s_x=1]\times P(x)\times P(y) \times a_y \]

拆一下式子,便于统计:

\[\sum _x s_xP(x) \times \sum P(y) a_y \]

其中 \(P(y)\) 的取值,并非原本的 \(P(y)\) ,而是在确定 \(x\) 参加舞会的条件下的 \(P'(y)\) 。这也是为什么统计祖先而非子树的原因。在求 \(P(y)\) 时,我们只需强制让 \(P'(x)=1\) ,即可按照 \(dp\) 方程求出。\(P(x)=\prod (1-P_{son_x})\times p_x\) 。直接暴力做复杂度是 \(O(nd)\) 的,其中 \(d\) 是整棵树的深度。

因为一次只会更新一个点,\(P'(fa)= P(fa)\times \frac{1-P'(son_x)}{1-P(son_x)}\) ,令 $v=\frac{P(fa)}{1-P(son_x)} $ ,因为 \(P\) 已经预处理好了,所以 \(v\) 是常数,而 \(P'(fa)=v-vP'(son)\) 。是 关于 \(P'(x)\)\(1\) 的线性变换,具体的:构造向量 \(\begin{bmatrix}1&f_u& sum_u\end{bmatrix}\) ,其中 \(f_u\) 即 被固定后的

Nfls 10.27

T2 完美主义

给定初始字符串的长度 \(x\) ,有以下四种操作

  1. 末尾加一个字符,代价 1
  2. 全选,代价2
  3. 复制,代价2
  4. 粘贴,代价2
  5. 退格,代价 1

求使字符串长度变为 \(y\) 的最少代价。

可以抽象成图论问题,并且如果初始长度比较大的话,一定是复制再粘贴,否则先打几个字符再复制,问题是复制完后,是粘贴若干次(这样中间不用选中再复制了),再复制,再粘贴一个长度更长的。发现粘贴若干次不会太多,最多也就16次左右。直接暴力建图。另外最短路长度是 \(O(n)\) 的,可以桶优化 Dij。

T3 挑战哈密顿 P6644 [CCO2020] Travelling Salesperson

给定一张完全图,边有Red,Blue 两种颜色,对于每个起点,求一条最短的哈密顿路使得每个点都至少经过一次,且经过边的颜色方案中,颜色只能变换一次,即 RRRR...RRRBBBB...BBB 或先 BR。 你需要输出构造出的路径。

结合链表的构造好题,结论是最短路一定可以做到长度为 \(n\)

对于当前起点 \(u\) ,已经构造好一条 合法的链,链的末尾是 \(y\) 。设当前插入的点是 \(v\) ,分类讨论。

  • 整条链只有一种颜色:

    如果 \((y,v)\) 颜色相同,那么直接插入到末尾即可。

    否则, \(v\) 是整条路径的颜色分界点。也插入到末尾。

  • 整条链已经有两种颜色:

    如果 \((y,v)\) 能直接插后面,就插后面。

    否则,设颜色分界点为 \(k\) ,不妨令前半段颜色为R,后半段颜色为 B

    • \((k,v)\) 颜色为 R ,则 \(v\) 插入到 \(k\) 的后面,\(v\) 成为新的分界点。
    • 否则,将 \(v\) 插入到 \(k\) 的前面,\(v\) 成为新的关键点。

    总复杂度 \(O(n^2)\)

但是!list 有点复杂了点:一些要牢记的边界处理:

list.insert(++k,x) 后要判断 if(k==list.end()) k-- 。虽然我也不知道怎么回事,但好像整体往前平移了一段?

T4 装备

给定若干个二元组 \((a_i,b_i)\) ,并保证 \(a_i\) 互不相同。你有 \(k\)\(swap(a_i,b_i)\) 的机会,需要保证 \(a_i\) 时刻互不相同。你想要使得 \(a_i\) 构成序列的字典序尽可能大。输出交换序列。

本题 trick 和 联合省选2023 Day2T2 填数游戏 几乎完全一样。

根据 \(a_i\) 互不相同,我们想到树的父亲是唯一的。

对于初始给定的每一个 \((a_i,b_i)\) ,建一条 \(a_i\) 指向 \(b_i\) 的有向边。最后形成若干个弱连通分量,对于每个分量,只可能是内向树或 内向基环树。对于一棵内向基环树,没有交换的空间。对于一颗内向树,只有根节点 没有入边,而这个根节点就是我们能留出“空”来交换的位置。

具体的,合法的状态体现在:每个点最多只有 \(1\) 条入边。交换的操作体现在:将一条边反向。我们想要反向一条边,此时 一个点一定会改变入度个数,如果这个点是根的话不用管,否则入度为 \(2\) ,需要将这个点到 根的路径全部反向,以消除这个影响。然后这条边连的另一条边成为新的根。

因为我们要使得字典序尽可能大,所以从左往右枚举,每次翻转后的边就固定好了,下次不能再动了。这样均摊复杂度就是 \(O(n)\) 的。

对于操作数,我们可以 dfs 的时候统计一下就可以,如果超过 k 就跳过这一轮。

联合省选d2T2 填数游戏

Nfls 10.28 分块专题

T2 疯狂星期四

有 长度为 \(n\) 的序列 \(a_i\) ,和 \(m\) 个函数 ,每个函数 \(f(i)\) 表示 \(\sum _{j=L_i}^{R_i} a_j\)

  1. 单点修改 \(a_x\to y\)
  2. 区间函数和, \(\sum_l^r f(j)\)

\(n\le 10^5\)

赛时一直在想应该不可做的 \(polylog\) 做法,感觉分块再带 \(log\) 非常吓人呀。不过实际上分块加log肯定能过 \(1e5\) 的。

大概是应该不均摊的均摊线段树+二维数点、、、如果把 懒标记改成 vector 的复杂度是多少呀。

讲讲正解,对外层函数分块。

也就是分成 \(\sqrt m\) 块,每块存函数和。这样区间整块和是简单的。考虑 \(a_i\) 会对第 \(j\) 块产生多少贡献,也就是 \(a_i\) 在这个块的出现次数。可以想到差分统计次数。也就是每个函数对所在块的次数贡献是区间 \([L_i,R_i]\) 加一。最后差分数组累加可以得到第 \(i\) 个块,\(j\) 的出现次数 \(cnt_{i,j}\) ,一个块的和初始就是 \(\sum cnt_j\times a_j\)

那这样单点修改也可以做了,对于 \(a_x=y\) ,求出变化量 \(\delta\) ,它对所有包含它的块都有贡献,也就是 \(cnt_{i,j}\times \delta\) 。然后 \(a_x=y\) ,这一步是 \(O(1)\) 的,显得有些快了。

对于区间查询,整块和有了,散块和怎么做?即 \(\sum _j\sum _{k=L_j}^{R_j} a_k\) 。树状数组是可以做到 \(O(\sqrt n \log n)\) 。考虑怎么不用树状数组,显然这是一个前缀和。考虑根号平衡:\(O(1)\) 查询区间和,\(O(\sqrt n)\) 单点修改。也就是每个块维护 第 \(1\) 到第 \(i\) 块的前缀和,块内维护块内前缀和。对于上面的 \(O(1)\) 修改就能改成 对 \(O(\sqrt n)\) 个块进行修改。达到根号平衡的效果。

调了挺长时间,问题在于对散块的处理大概率是不对称的,不要直接复制或者比着写。

T3 一九八四

给定一个 \(n*m*h\le 10^5\) 的空间,要求支持:

  1. \((x,y,z)\) 位置插入一个点
  2. 询问离 \((x,y,z)\) 距离最短的点,距离指曼哈顿距离。

So1.错解

三个数相乘的结果小于 \(10^5\) ,则中间数的大小 \(b\) 不会超过 \(\sqrt {10^5}=400\) 。将中间这一维定成枚举维,切割成若干个平面。每个平面存平面的答案。但是平面的大小并非根号级别的,反例:1 10 100000

Sol2.定期重构:时间分块

适用于解决:修改间相互独立 的问题。每次加入一个点,并不会对别的点产生影响。

我们设 \(ans_x\) 表示 \(x\) 点的最近距离,这样直接做,查询是 \(O(1)\) ,修改是 \(O(n)\)

但是我们可以每 \(\sqrt{q}\) 次修改就重构一遍 \(ans\) 。这样每次重构用洪水填充算法,将需要重构的点扔进队列。复杂度 \(O(n)\) 。每次询问,先查 \(ans\) ,再暴力枚举 \(O(\sqrt n)\) 个没有重构的点的距离。总复杂度 \(O(n\sqrt n )\)

T4 旅行

给定一棵树,边有边权 \(w\in [1,2]\) ,每次询问从 \((u,v)\) 这条路径,每天最多走 \(k\) 公里,晚上必须在节点留下。需要多少天可以到达。

Sol:根号分治

对于 \(k\ge \sqrt n\) 的情况,最终结果不会太多,所以二分暴力跳即可。

对于 \(k<\sqrt n\) 的情况,小块是很好做的,预处理出 \(f_{u,j,k}\) 表示 \(u\) 向上跳 \(2^j\) 天,每天最多 \(k\) 步,能到达哪个点。

时间应该够,空间可能不大够,离线下来对于 \(k\) 相同的统一处理。这样空间复杂度就只有 \(O(n\log n)\) 了。

代码实现上,注意怎么跨过 \(lca\),最后如果 \(x,y\) 都在 \(lca\) 上则不管,否则 这一段距离要么跳一段,要么跳两段。

Nfls 10.30

T2 药品实验【2019数学高考】

给定 \(n,a,b,c\) 其中 \(a+b+c=1\) ,设 \(p_i=ap_{i-1}+bp_i+cp_{i+1}\) 。已知 \(p_1=0,p_{2n}=1\) ,求 \(p_n\)

高考数列题,原题第一问要求证 \(\{p_i-p_{i-1}\}\) 是等比数列。

\[p_i=ap_{i-1}+(b+c)p_i+c(p_{i+1}-p_{i}) \\ p_i-(b+c)p_i-ap_{i-1}=c(p_{i+1}-p_i) \\ \Longrightarrow a(p_i-p_{i-1})=c(p_{i+1}-p_i) \]

公比是 \(k=\frac{a}{c}\)

所以 \(\sum (p_i-p_{i-1})=p_{2n}=1\) ,其中首项 \(p_1-p_0=p_1\)\(p_1\times \frac{1-k^{2n}}{1-k}=1\) ,可得 \(p_1=\frac{1-k}{1-k^{2n}}\)

又因为公差知道, \(p_n\) 就可以递推地算出来,当然可以矩阵加速。

T3 小猫钓鱼

\(n\) 个人打扑克,每个人初始有 \(l\) 张,类型和排火车类似,有超级派,可以把所有牌都收起来。\(n,l\le 100\) 。求 \(T\) 轮后每个人手里的牌。\(\sum T=10^6\)

时间复杂度计算题,模拟实现即可,需要离散化或者 unordered_map

复杂度 \(O(Tn)\) 为什么是对的?首先添加牌和收走牌数量的复杂度是相等的,一轮比赛只能增加 \(n\) 张牌,所以均摊会收走 \(O(n)\) 张牌。

T4 模拟旅行

给定一个集合 \(S\) 内有若干个点,求这个集合中任意两点在有向图中最短路的最小值。

kdw说是 BCT 原题,但是正好那天没讲图论,哈哈。

特殊点问题首先考虑建虚拟源点/虚树。现在考虑虚拟源点,向每个特殊点连一条边。边权为 \(0\)

这样可以得到所有经过至少一个关键点的最短路 \(d_u\) 。但是我们不知道经过的是哪个关键点,设 \(f_u\) 表示,最短路松弛的时候一块求就行。

Sol1 二进制分组

特别适合这样的分组问题。

作为答案的两个点的编号一定有一位二进制不同。那我们枚举二进制位,将这一位是 \(0\) 的关键点分为一个集合,为 \(1\) 的分为一个集合。连虚拟源点跑两遍最短路。枚举终点组的答案。复杂度 \(O((n+m)\log m\log k)\)

Sol2.反向图

考虑作为答案的两个点 \((u,v)\),他们之间的路径一定是一段经过 \(u\) 的最短路径,再接着跳到一段经过 \(v\) 的最短路径。或者说是从 \(u\) 出发走最短路,接着切换到从 \(v\) 出发的最短路。后者是反图上的。

形式化地, \(dis=d_x+w+d'_y\) ,满足 \(f_x=u,f'_y=v\)\((u,x),(y,v)\) 均为最短路。

时间复杂度 \(O((n+m)\log m)\)

Div1 T4 迷雾华光

在线算法求树上众数。

区间众数:蒲公英,一种简单的方法是设 \(f_{u,v}\) 表示 \([u,v]\) 块之间的区间众数是谁,\(g_{u,x}\) 表示前 \(u\) 个块内 \(x\) 出现了多少次,时间空间复杂度均为 \(O(n \sqrt n)\)

考虑搬到树上,随机撒关键点,对于 \((u,k_1)\to(k_1,lca)\to (lca,k2)\to (k2,v)\) 这样的路径,中间是整块,两边是散块。需要特判 \(lca\) 的情况。

Nfls 10.31

T3 小 G 的布料

给定一个 \(n*m\)\(01\) 矩阵,求面积大于等于 \(k\) 的全 \(0\) 子矩阵个数。 \(n\le3000\)

小清新并查集线性做法

并查集算 \(O(1)\)

先预处理出 \(f_{i,j}\) 表示 往下有多少连续的 \(0\) 。对于每一行,我们按照矩形高度递减地加矩形,每次加一批高度相同的新的全 \(0\) 矩形都会形成一批新的矩形连通块,用并查集维护连通性,我们只需统计这些新生成的连通块。可以用 vector 记录第 \(i\) 行,高度为 \(j\) 的矩形是哪些。

考虑每次形成一个新的连通块,该连通块的左端点为 \(L\),右端点为 \(R\) ,当前高度为 \(h\) 。统计它带来的贡献,注意到此时 \(L-1\)\(R+1\) 处的矩形都没有添加进来,为了保证不重不漏,我们只统计高度 \(k\in[\max(f_{i,L-1},f_{i,R+1})+1,h]\) ,宽度 \(w\in[1,R-L+1]\) 的合法矩形数量。这个东西提前预处理前缀和即可。

T4 Easy Data Structure

给定一二进制表达式树,包含三种基本二元运算操作,每个叶子有 \(p\) 的概率是 \(1\)\(1-p\) 的概率是 \(0\),求根为 \(1\) 的概率。支持修改叶子的概率。

树上动态dp,基本思想是树剖后,每个节点的矩阵表示的是,其重儿子为 \(0/1\) 时,自己为 \(0/1\) 的概率,即一个 \(2*2\) 的矩阵。每次修改,先修改这个点,再修改这个点到链顶,可以线段树做,然后跳一条轻边。。。以后再来学习吧。

Pyyz 11.2 Day1 by ZYW

T1 矩阵优化

T2 字符串

定义一个长度为 \(n\) 的字符串的价值是:这个字符串所有长度小于等于 \(\frac{n}{2}\) 的 border 的长度之和。

求给定字符串所有子序列的 border 价值之和。 \(n\le300\)

暴力非多项式复杂度的,有关子序列的, 考虑 dp,设 \(dp[i][x][y]\) 表示 border 长度为 \(i\) 的子序列,前半段结尾于 \(x\) ,后半段结尾于 \(y\) 。有转移:

$dp[i][x][y]=\sum dp[i-1][x'][y'] $ ,满足 \(s[x]=s[y]\) 。答案就是 \(\sum_i\sum _p dp[i][x][y]\times i \times 2^{p-x+1}\) 。其中 \(p\) 是枚举的后半段开头的位置,需要满足 \(x\le p\)

转移的式子不难可以前缀和优化。

这样做枚举答案复杂度是 \(n^4\) 的,发现我们不需要记录 \(i\) 这一维。可以用 \(g[x][y]\) 表示这样的 \(f[x][y]\)\(\sum i\) 是多少,本质仍是乘法对加法有分配率。

\(g[x][y]=\sum g[x'][y']+f[x][y]\) 。答案是 \(\sum f[x][y]\times g[x][y]\times 2^{p-x+1}\) 。复杂度为 \(O(n^3)\)

T3 通讯公司

\(n\) 个人 ,\(m\) 个通讯公司,每个通讯公司包含若干人(用集合 \(S_i\) 表示),同一通讯公司下的用户可以互相拨号,一个人最多可以向一个人发出拨号,但可以同时收到多个人的拨号。 \(x\)\(y\) 拨号的收益为 \(a_x\times a_y\) ,但是两个人互相拨号的收益仍然是 一倍。求某一时刻总收益最大是多少。

\(n\le 10^5,\sum |s_i| \le 10^5\)

我完全不会 最小生成树。

考场上一直在模仿【省选D2T2 填数游戏】的 trick 去搞 内向基环树的换根,但这样是完全没有必要的,因为我们毫不关心基环树边的方向,也就是当成无向图看就行,一直没想到点权转边权,直接暴力建图,将一条边 看做 \(a_x\times a_y\) ,做最大基环树即可,实现和 kruskal 基本一样 ,最多一个环。

但这样做复杂度太大了,建图的复杂度就是 \(O(\sum |s_i|^2)\) 的。我们观察加入到最大生成树的边,一定是一个集合内,最大点所连出的边,和次大点所连出的边,因为这些边就足以构成一棵基环树了。

T4 dp of dp

害怕。别考。

Day2 by ZYW

T1 小数点

给定一个分数 \(p,q\),求 \(\frac{p}{q}\) 的第 \([l,r]\) 位。\(l,r\le 10^9,r-l\le 10^5\)

好题,考场上想了半小时的数论意义,发现小数循环节的长度 \(len\) 是最小的满足 \(10^{len}=1\mod q,q\ne2k,5k\) 的正整数,然后 BSGS?NOI Plus模拟赛。

但实际上根本没有这么麻烦,问题关键在于快速幂不能取模,先把式子写出来:

$ \lfloor \frac{10^Lp}{q}\rfloor \bmod 10 \Longleftrightarrow \lfloor\frac{10^Lp-10q}{q}\rfloor \bmod 10\Longleftrightarrow \lfloor\frac{10^p\bmod 10q}{q}\rfloor \bmod 10$ 。这样就能取模了

启示:对于在数论模意义下难以解决的运算,例如向下取整等,可以考虑其等价的效果,也就是减去一个数,仍然相等,相当于对这个数取模。

另外,别遇到小数题就想你那模意义了。

T2 体力劳动

给定序列 \(a_i\)\(x\) ,求一个最小区间长度 \([l,r]\) ,满足区间逆序对个数 \(\ge x\)

区间长度有单调性,相当于二分答案。然后 check 类似滑动窗口,减去左边一个数,和增加右边一个数,对逆序对产生的贡献都是主席树方便维护的。

T3 距离之和

给定一棵树,一次操作支持删除一条边,再添加一条边,使图仍然保持树的形态,求对于每个点,变成树的重心,所需要的最小操作数。

一个点是树的重心的充要条件是,所有子树的大小都小于等于 \(\frac{n}{2}\) 。一棵树可能有两个重心。

考虑 \(u\) 号点,首先,我们先断掉一定数量的边,然后连边的时候,全部连到 \(u\) 上一定最优。所以我们只需考虑删边怎么删,无需考虑连边怎么连。

删边后的图,需要满足, \(u\) 所在连通块内,每个儿子的大小都小于等于 \(n/2\) ,除 \(u\) 所在的联通块外,每个连通块大小都小于等于 \(n/2\)

对于原图(即给定的图中),记树的重心为 \(rt\) ,将无根树变成以 \(rt\) 为根的有根树后,我们删边,一定可以选择全部删与 \(rt\) 直接相连的边,因为这样得到的连通块仍然满足条件。

我们从大到小砍 \(u\) 的所有子树,直到剩下的大小小于一半,记操作数为 \(x\)

分类讨论:

  1. \(u\) 的除 \(rt\) 外最高的祖先为 \(b_u\) ,如果在得到 \(x\) 的删边过程中,\((b_u,rt)\) 被删除,且连上这条边,\(u\) 仍然保持合法,则答案为 \(x-1\)
  2. 如果 $(b_u,rt) $ 未被删除,若将 \(x\) 对应方案中,砍掉的最小子树连回去,如果合法,则答案为 \(x-1\)
  3. 否则,答案为 \(x\) ,可以证明,答案不会更优(。

至此,答案只可能是 \({x,x-1}\) ,时间复杂度做到了严格线性。

T4 崇拜

给定一棵树,求 :

\[\sum _{p是一个1到n的排列} \prod dep[lca(p_i,p_{i+1})] \]

$n\le500 $ 。

考虑状压,即 \(n\le20\) 怎么做。

Day3 by Smeow

T1 猫猫小游戏

给出一个 \(n*m\) 的网格,有两种颜色,初始均为无色。有两种操作:

  • 选择一行染成红色
  • 选择一列染成蓝色

问是否可以染成目标状态。 \(n,m\le3000\)

考虑无法染成目标状态,即形成一个类似环的结构,想到建立图论模型。

首先,重复染多次是没有意义的。一个方格 $(i,j) $ 最后颜色是 红色,说明蓝色一定在红色前被染过,则建立一条 \(j\to i\) 的边,合法的染色顺序即这张图的拓扑序,不合法只需判断是否有环即可。

T2 猫猫的数列

求满足下列条件,长度为 \(n\) 的序列 \(A\) 有多少个:

  • \(a_i\le m\)
  • 有且仅有一对元素数值相同。
  • 存在一个位置 \(p\) ,使得 \(a_1,a_2,...a_p\) 严格单调递增,\(a_{p},a_{p+1}...a_n\) 严格单调递减。

\(n,m\le 10^{15},mod\le 10^6\)

完全不会类似的组合题呀,考场上写的什么 \(n^3\) 瞎 dp 还贼难调。Orz Setoff...

第一步,\(A\) 中的数字有几种?

  • 由于有一个是相同的, \(\binom{m}{n-1}\)
  • 对于剩下那一个数,要选择一个不是最大的和他相等,即 \((n-2)\)

第二步,这些数字怎么放?

  • 先除去两个相等的,最大的那一个一定放中间,剩下的,每一个都可能放左边,可能放右边,且无论放左边还是右边,都只有唯一的位置\(2^{n-3}\)

答案即为三者相乘。

注意到模数很小,使用 \(Lucas\)

T3 多重集的错位排列

给定非排列的 \(a_i\),求有多少种改变顺序得到的 \(b_i\) ,满足 \(\forall \ b_i\ne a_i\)\(n\le2000\)

普通错排的递推式就是 \(D(n)=(n-1)\times (D(n-1)+D(n-2))\) ,就是考虑最后一步,是交换之前的一个错排,还是之前的一个非错排。

但是错排还有容斥形式,至少一个的容斥系数就是:(固定零个)-(固定一个)+ (固定两个)-(固定三个)+(固定四个)...

即:(刚好打破 \(0\) 个限制)=(至少打破 0 个限制)-(至少打破 1 个限制) + (至少打破两个限制) - (至少打破三个限制)...

写成封闭形式,即 \(D(n)=\sum (\binom{n}{i}(-1)^i\times(n-i)!)\)

回顾一下容斥原理的本质:容斥系数为正的时候,是为了求出那些最后一次有机会能求出的数。

另外,对于多重集的全排列公式,即 \(\frac{n!}{n_1!n_2!n_3!...n_k!}\)

考虑 \(dp\) ,设 \(f[i][j]\) 表示考虑了 \(i\) 个数字,\(j\) 个位置强制打破。数组值存的是 容斥系数×方案数。

枚举当前数字 \(i\) 强制打破了 \(k\) 个限制, $f[i][j]=\sum f[i-1][j-k]\times (-1)^k\times \binom{siz[i]}{k}\times \frac{1}{(siz[i]-k)!} $ ,和上面基本一样。

最后答案即 \(\sum f[m][i] \times (n-j)!\)

T4 括号

给定一个长为 \(n\) 的括号序列,支持三种操作:

  • 将第 \(x\) 个位置的括号替换为左/右括号
  • 查询该括号序列是否为合法括号序列。

套路题,将左括号看做 +1 ,右括号看作 -1 ,合法括号序列满足前缀和最小值 \(\ge 0\) 且最后一位 \(=0\) 的限制。直接线段树做即可。

Day 4 by Smeow

T1 文学游戏【FST-10】

T2 数学游戏

\(n\) 个数字,你可以消掉任意个质因数 \(>1\) 的数字(相同质因子只算一次),也可以使用一次数字复制器,使得 \(a_x\)\(a_y\) 都变成 \(a_x\times a_y\) 。给定 \(q\) 次询问,每次询问 \([l,r]\) 的数字至少需要多少次复制器才能全部消掉。 \(n\le 10^5\)

显然需要将所有数字质因数分解,只有一个质因子的数是删不掉的,必须和有另一个质因子的数结合。分类讨论:【下文中,质数代指质数和只包含一个质因子的数】

  • 这个区间里只有 \(1\) 和一个质因子,消不掉,输出 -1
  • 对于 \(1\) ,一次只能拿 \(1\) 和合数消,若没有合数,输出 -1
  • 这个区间里,出现次数最多的质数小于所有数的一半,那么每次消都可以消去两个。
  • 否则,存在绝对众数,剩下的那些,一次只能消一个。

摩尔投票维护区间众数即可。

T3 地理问题

给定一张无向图,你需要给边定向,有若干条指令,要求你从 \(u\) 能走到 \(v\) ,问你何时无法满足所有指令【即指令间出现矛盾】。

图上问题很难处理,我们希望扔到树上去,考虑边双缩点,因为一个边双内,存在一个方案使得所有点两两可达的。所以我们不需要管边双内的情况。只需要管割边即可。

缩点后形成一棵树,直接树剖打 【从上到下】或者【从下到上】的标记,如果一条边同时存在两个标记,则说明非法。

T4 历史问题

给定序列 \(a_i\) , 每次询问区间 \([l,r]\) 的连续段个数有多少。一个 \([l,r]\) 是连续段,当且仅当 \(\max-min=r-l\)

强制在线, \(n,q\le 10^5\)

首先考虑离线怎么求,扫描线左端点,设 \(f_i\) 表示左端点确定,右端点为 \(i\) 时,这段区间的【数值段】个数,例如【1,2,3】【5,6】,【8】的个数为 \(3\)

类似 【bakery】的思路,考虑加入一个 \(a_i\) 的贡献是什么。找到 \(a_i-1\)\(a_i+1\) 在前面出现的位置,排序后分别记作 \(pre_1,pre_2\)

那么会对 \([1,pre_1]\) 区间减一,因为两个连续段合并, \([pre_1+1,pre_2]\) 区间不变, \([pre_2+1,i-1]\) 区间减一,因为又多了一个连续段。

当然对只有 \(pre1\) 的情况要特判。

统计就是 【=1】的个数,即最小值个数,是线段树好维护的。

那么在线呢?变成一个历史和了>....< 这下成【NOIP2022】模拟赛了

Day5 by wucsdtio

T1 序列函数

定义 \(f(a_1,a_2,...,a_n)=f(a_1\oplus a_2,a_2\oplus a_3,...,a_{n-1}\oplus a_n)\) 。每次给出一个区间 \(l,r\) ,求 \(\max_{l\le i\le j\le r} f(a_i,...a_j)\)

\(f\) 函数直接做是非常不好做的,但是可以通过样例观察出 $f(l,r)=f(l,r-1)\oplus f(l+1,r) $,另记 \(g(i,j)=\max_{i\le l\le r\le j} f(l,r)\)

\(g(i,j)=\max (g(i,j-1),g(i+1,j),f(i,j) )\) 。做到 \(O(n^2+m)\)

T2 历史

给出一棵树,每次选择一个点和权值 \((x,val)\) 。所有和 \(x\) 距离小于等于 \(val\) 的点的 \(w_i\) 都会加上 \(max(val-dis,0)\) 。最后统一求每个点的 \(w_i\)\(val\le1000\)

相当于一个点不断向外扩张,扩张的过程类似一个等差数列,末项为 \(0\)

发现 \(val\) 比较小,考虑和 \(val\) 有关的复杂度。

问题在于标记是不能“合并“的,因为如果一个权值为 \(4\) 的标记和一个权值为 \(5\) 的标记合并成一个权值为 9 的标记,就不能判断其在什么位置结束为 0 。但是同样权值的标记是可以合并的,记 \(d_{u,v}\) 表示 \(u\) 点有 \(d_{u,v}\) 个大小为 \(v\) 的标记,转移为 \(d_{u,v}\to d_{u',v-d_{u,v}}\) 。空间复杂度有点汗流浃背了:\(O(n\times val)\)

Sol1.换根dp

最后统一处理答案,可以直接换根做: \(f_{u,i}\) 表示以 \(u\) 为根的子树,对 \(u\) 点贡献为 \(i\) 的个数。

\(f_{u,i}=\sum f_{v,i+1}\)

\(g_{u,i}\) 表示 \(u\) 除子树外的部分(这样设比较好算),对 \(u\) 贡献为 \(i\) 的个数:

\(g_{u,i}=g_{fa,i+1}+\sum _{v\in son_{fa},v\ne u} f_{v,i+1}\) 。 时空复杂度均为 $O(nd) $ 。

平邑第一换根中学。

胜利第一点分中学。

T3 附魔

\(n\) 本附魔书,第 \(i\) 本附魔书初始有魔咒 \(i\) ,该魔咒对应的经验等级 \(a_i\) ,和合并过程中的累计惩罚 \(v_i\) 初始为 \(1\)

每次进行两本附魔书的合并,若将 \(x\) 合并到 \(y\) 上,则 会消耗 \(x\) 上所有魔咒的 \(a_i\) ,以及惩罚 \(v_y\) 的代价。同时 \(v_y=v_y\times 2\)

问将所有附魔都附魔到一本书上的最小代价。

显然构成了树形结构,但是需要我们找性质。

  • 一个魔咒的经验等级 \(a_i\) 被计算的次数,等价于其在原树的深度。因此应该将 \(a_i\) 大的填上面, \(a_i\) 小的填下面。
  • 一个点获得的惩罚,与其儿子的数量 \(x\) 有关: \(\sum_i^{x} 2^i=2^x-1\) 。因此,一个点不应该有过多儿子,将儿子挂到该层上另一个儿子少的点上,一定不劣。

综上,我们可以规范化地得出结论(这里定义度数是儿子数量。

  • 同一层上每个点的度数最多差 \(1\)
  • 父节点的度数一定大于等于子节点度数,否则把子节点挂到上一层不会劣。

也就是说,我们按照 bfs 的过程得到的每个点的度数,一定是一个不增的序列。然后就可以 DP 了,设 \(dp[i][a][b]\) 表示当前层的第一个节点为 \(i\) ,这一层有 \(a\) 个节点,下一层有 \(b\) 个节点,需要枚举每一层的度数。

T4 曼哈顿

给定一张网格图,你需要遍历每个点并回到起点,每一次移动的价值是两点间的曼哈顿距离。问价值最大是多少?

转换:等价于每一条网格线被跨过的次数之和。

思路:构造理论最大值。

对于一条线,其左边有 \(a\) 个点,右边有 \(b\) 个点,被跨过的理论最大值就是 \(2min(a,b)\)

然后,如果最中间的线达到了理论最大值,则其他平行与他的线也达到了理论最大值。

于是只需考虑最中间的横线和竖线。

那么考虑一张 \(2*2\) (偶数×偶数)的图,手摸发现构造不满,是理论最大值-2。

再考虑有奇数的情况,最中间的线有两条,也是一样道理。

Day 6 by wucsdtio

T1 铺设积木 roadblock(2013,2018,2023)

差分练习题,+没用的oi冷知识

T2 开关灯

\(n\) 盏灯,初始全为 熄灭,对于第 \(i\) 次操作,选择 \(i\) 的所有质数倍标号的灯,并把他们状态翻转。

\(n\) 次操作后,有多少灯是开的。 \(n\le5\times 10^7 ,10^{10}\)

不妨分块打表

一开始可能不是很好线性筛,但是如果将开灯设为 \(f=-1\) ,关灯设为 \(f=1\) ,那么对于 $x=p_1{q_1}...p_m $ , \(f(x)=(-1)^m\) 。很好的形式。满足非完全积性函数的性质,\(f(xy)=(-1)^{m1+m2},\gcd(x,y)=1\)。可以进行线性筛。剩下的留给亚线性筛。

T3 历史 Plus2.0

给出一棵树,每次选择一个点和权值 \((x,val)\) 。所有和 \(x\) 距离小于等于 \(val\) 的点的 \(w_i\) 都会加上 \(val\) 减去距离的值。单点询问 \(w_u\) 的值,\(val\le 10^9\)

和上一题不同的是,不再受 \(0\) 的限制,但值域也升到了 \(1e9\) ,并且需要支持过程中查询。

一眼根号重构吗这不是。散块直接找距离,可以用线性 lca。重构直接借助昨天的思路——换根dp。

\(cnt_u\) 表示 \(u\) 子树内这样的点的个数, \(f_{u}\) 表示 \(u\) 子树内,所有点对 \(u\) 的影响。 \(g_u\) 表示 整棵树对 \(u\) 的影响。

\(cnt_u=\sum cnt_v+[u],f_u=\sum (f_v+cnt_v)+val_u\)

\(g_u=g_{fa}+cnt_u-(cnt_1-cnt_u)\)

这样 \(O(n)\) 就可以根号重构了,复杂度不多带 \(\log\) 。跑的飞快。

对于 \(polylog\) 的做法,考虑这东西就是一个树上加等差数列。

T4

Day7 by chunzhen

T1 树的直径,T2 slyz模拟赛T4 \kt\kt。

T3 Yazid 的新生舞会

给定序列 \(a_i\) ,求有多少区间 \([l,r]\) 满足存在区间绝对众数。

Sol1.根号分治

问题首先转换为枚举每个值 \(x\) ,将所有等于他的设成 \(1\) ,否则设成 \(-1\) ,这样一个区间有绝对众数,等价于存在一个区间的和大于等于 \(0\) 。复杂度 \(O(n^2\log)\)

第二步的操作就很想根号分治,对于一个数出现次数大于 \(B\) 的,则这样的数不会超过 \(n/B\) 个。可以直接暴力。否则,对于每一个这样的数,其可能会作为一个区间众数的区间长度都不会超过 \(2B\) 。我们可以最后统一扫一遍,复杂度 \(O(n^2\log/B+n\times2B)\)\(B=\sqrt{n\log}/2\) 左右比较好。复杂度 \(O(n\sqrt{n\log n})\)

Sol2.三阶差分树状数组 线段树

一个区间的和大于等于0,本质就是求前缀和数组的顺序对。注意观察前缀和数组,因为有大量 \(-1\) 的存在,所以相邻两个 \(x\) 之间的一堆 \(-1\)\(s\) 数组上的体现就是公差为 \(-1\) 的等差数列,即一段 \([s,e]\) 。开一个桶 \(c\) 记录。再开一个桶 \(d\) 记录 桶 \(c\) 的前缀和。

Sol3.分治

很容易想到分治结构,一个数能够作为当前区间的绝对众数,要求出现大于一半,那么他一定是左儿子的绝对众数或右儿子的绝对众数。

T4 仓皇逃跑 √

给定一棵树,以及多条路径,边有 \(k\) 种颜色,每条路径要求这条路径上至少有两种颜色,问满足条件的树有多少种可能。\(n\le60,m\le15,k\le10^9\)

考场上爆写 subtask 怒切 60分。

考虑只有两条路径且相交的情况怎么做,需要分类讨论:相交部分有一种颜色还是两种颜色。

很麻烦,但是可以将问题容斥一下,转换成一条路径上只有一种颜色。这很方便用并查集维护。并且数据范围小,可以直接容斥。

也就是枚举不合法边组成的集合 \(S\) ,对于每个集合的容斥系数为 \((-1)^{popcount(S)}\) ,对于相交的路径压成一条,枚举即可。

Day8 by WHQ

T1 分数约分

爆搜。但写挂了

T2 共享单车

学校看做一张无向图,有 \(k\) 个点上有共享单车,汽车速度是 \(y\) ,步行速度是 \(x\) ,但是第 \(i\) 辆单车有 \(p_i\) 的概率开锁失败,问从起点到终点,采取最优策略的最小期望时间是多少? \(n\le10^5,k\le 18\)

考虑一档 \(n,k\) 同阶,非DAG的图上 dp 是非多项式的,直接考虑状压,表示走过了哪些点。倒序枚举,然后就可以 \(dp\) 无后效性地转移了。

如果 \(n\) 更大,发现处理其他的点都是没有意义的,我们只关心有单车的 \(k\) 个点,预处理 \(k\) 个点间两两最短路即可。

T3 积木拼接

给定 \(n\) 个字符串 \(s_i\) ,选出一个子序列,满足是回文串的方案有多少? \(n\le 100,\sum |s|\le 10^5\)

不会

T4 [六省联考 2017]

维护一个数据结构,支持:

  1. 给定 \(x,l,r\) ,将区间 \([l,r]\)\(a_i\to x^{a_i}\)
  2. 给定 \(l,r\) ,输出 \(\sum a_i\bmod p\)

\(n,m\le 5\times 10^4\)

本题暴力就比较难做,修改是不带取模的,查询是要带取模的。

首先需要拓展欧拉定理:

\(a^x=a^{x\bmod \phi(p)} \mod p\)\(a^x=a^{(x\bmod \phi(p))+\phi(p)}\mod p\) 。(不互质)

因此我们需要维护的是,一个类似幂塔的结构,即 \(x_1^{x_2^{x_3^{a_i}\bmod \phi(\phi(p))}\bmod \phi(p)}\bmod p\)

另外, \(p\to \phi(p)\to \phi(\phi(p))\) 是呈指数下降的,因为对于一个奇数会变成偶数,一个偶数至少会减半。所以至多 \(O(\log )\) 次模数变为 \(1\) ,上面的部分就不用管了。

因此线段树上一个位置维护一个队列,时刻保持队列的长度是 \(\log\) 以内即可。

复杂度多一个 \(\log\) 在矩阵乘法上,预处理光速幂即可。

Day9 by lxl

T1 查询

给定三个序列 $a,b,c $。求 \(a_j+b_j\times c_i\) 的第 \(k\) 小值。

\(k\) 小单调队列,第 \(k\) 小二分答案。二分答案后检查小于 \(x\) 的个数,枚举一维 \(j\) ,显然 \(i\) 有单调性。

T2 枚举

给定 \(x,y\) ,求三元组 \((a,b,c\le n)\) 的个数满足 \(((x^2+1)\bmod a+b)\bmod c=y\) 。同时需要输出字典序前 \(10^5\) 小的三元组。

先考虑一个 \(O(n^2)\) 做法,枚举作为模数的 \(a,c\) 。此时 \(b\) 是一个区间,然后我们可以直接加到 \(vector\) 里直到超过 \(10^5\) ,最后再排序。

尝试把取模展开,记 \(z=(x^2+1)\bmod a+b\)\(\lfloor\frac{z}{c}\rfloor\times c+z=y\) 。枚举 \(c\)\(\frac{z}{c}\) ,这样是调和级数的。

这样得到合法的 \(a,b\) 的个数也是 \(O(n\lg n)\) 的。

T3 决斗 √

\(A\)\(B\) 决斗扑克牌,\(A\) 先手,已知 \(A,B\) 的出牌序列,\(B\) 事先知道 \(A\) 的出牌顺序。规则是点数大的获胜。 \(B\) 只希望他获胜的局数尽可能多。而且出牌的字典序要尽可能大。输出出牌顺序。

最多的获胜局数是比较简单的,采用田忌赛马的战略,每次 \(B\) 出大于 \(A\) 的最小的,如果没有就出自己最小的。这样我们可以得到第一问的答案。

但这种策略和第二问是矛盾的,字典序问题逐步确定答案,不难发现每一步能出的牌是一个区间,我们要填这个区间的最大值。且不会影响答案。

使用线段树的信息合并解决带修改问题,将原问题扔到数轴上, \(A\) 的数字记作 \(a_i\)\(B\) 的数字记作 \(b_i\) 。一个序列上区间的最多获胜局数 \(ans\),本质就是每一个 \(a_i\)\(b_i\) 的匹配,记 \(ans\) 为答案, \(cnta\) 为剩下了多少个 \(a_i\)\(cntb\) 为剩下了多少个 \(b_i\)\(ans[p]=ans[ls]+ans[rs]+min(cnta[ls],cntb[rs])\)\(cnta[p]=\sum[a_i] -ans[p]\)\(\sum[a_i]\) 为原序列上 \(a\) 的总个数。

又因为 最大值是有单调性的,所以可以枚举一个 \(i\) 代表当前填第 \(i\) 个位置,二分一个 \(mid\) ,线段树上进行 \(i\) 这个位置上删除一个 \(a_i\)\(mid\) 上删除一个 \(b_i\),检查根节点的答案是否只减少 \(1\)

优化到单 \(\log\) 可以线段树上二分。

T4 Bamboo#2

Tag:时光倒流

\(n\) 棵柱子,初始高度为 \(h_i\) ,每天都会长高 \(a_i\) ,每天长高前,你有 \(k\) 次机会去砍竹子(可以砍同一棵),每次砍的高度都是 \(p\),但是竹子不能被砍成 \(0\) ,问 \(m\) 天后最高柱子最矮是多少。

时光倒流的好题,首先二分答案 \(mid\) ,因为有 \(0\) 的限制,问题转换成初始竹子高度都是 \(mid\) ,每天可以拔高 \(k\) 棵竹子,竹子自己会变矮 \(a_i\) ,问能否使得最后所有竹子高度都大于等于 \(0\)

此时,竹子拔高不再受 限制,也没有 \(h_i\) 的限制。直接贪心做是对的,用堆维护每个竹子到 \(0\) 的时间即可。

Day9+1 by lxl

T1 树

树上黑白染色,先手染黑色。如果最后存在一个黑点周围没有任何一个白点,则黑点胜,问先手是否有必胜策略。

又是被 T1 创死的一天,先观察链怎么做...只要链长度是奇数,先手都能胜利,首先三个节点的情况是先手必胜的,然后对于其他的奇数,都可以通过选择左数第二个点,而转换成先手必胜的子问题。

菊花要更简单一些,只要大于一个点,那么选择中心节点,下一步就能赢。

再分析一下策略:先手尽可能选择叶子的父亲,诱惑后手选择至少一个叶子,如果有多个叶子就赢了。

对于有一个叶子的情况,可以认为是:同时删去这两个节点,如果一个点被删两次,则先手赢

T2 异或 popcount

\(q\) 组询问,给定区间 \([l,r]\) ,对于每个 \(k\in[0,31]\) 求多少组整数对 \((x,y)\in[l,r]\) ,满足 \(x \oplus y\)\(k\) 个二进制为 \(1\)

数位 DP

T4 萌萌哒在线询问版

给定一个字符串,每次两种操作:

  1. \([l,r]\) 是一个回文串
  2. 询问 \([l1,r1]\)\([l2,r2]\) 是否相等。

首先可以转换为:正反各建一个哈希表,这样就转换成了 萌萌哒的在线询问。

本来萌萌哒是离线 ST 表,为了支持在线,我们使用线段树维护哈希。

暴力做问题在于合并的次数太多,而有些点是合并过多次而没有必要的。

对于修改两个区间相等的操作,我们不断二分,找到第一个满足子段哈希不相等的位置,然后将两个不相等的位置合并,并将两个子段的哈希修改成相等。

这样总合并次数是 \(O(n)\) 的,每次二分查找+线段树是 \(O(log^2)\) 的,因为我们需要记录并查集内具体是哪些点,所以启发式合并。

void merge(int u,int v) {
    u=find(u); v=find(v);
    if(u==v)
        return;
    if(vec[u].size()<vec[v].size())
        swap(u,v);
    for(auto x:vec[v]) {
        update(1,x,u);
        vec[u].push_back(x);
    }
    fa[v]=u;
    vec[v].clear();
}
int get_diff(int l1,int r1,int l2,int r2) {
    int l=1,r=r1-l1+1,ans=-1;
    while(l<=r) {
        int mid=(l+r)>>1;
        if(query(1,l1,l1+mid-1)!=query(1,l2,l2+mid-1))
            ans=mid,r=mid-1;
        else
            l=mid+1;
    }
    return ans;
} q
while(m--) {
    int l1,r1,l2,r2;
    scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
    while(true) {
        int val=get_diff(l1,r1,l2,r2);
        if(val==-1)
            break;
        merge(l1+val-1,l2+val-1);
        l1+=val; l2+=val;
    }
}
posted @ 2024-03-04 10:11  Apricity8211  阅读(33)  评论(0编辑  收藏  举报