雅礼2019省选集训小结

3-17

str

题意

一个只含有 A,C,G,T 的字符串 S ,把每个子串最小表示,求有多少个本质不同的子串。

数据范围

|S|105

题解

题面提示了一下后缀数组,就想了一下 SA 如何求本质不同子串数,其实就是把所有后缀从小到大排个序,然后减一下相邻两个 LCP 的长度就行了。

如何扩展呢?看到字符集十分的小,我们把每个后缀求出它最小表示的映射,然后对于 4!=24 种映射全部预处理 Hash

最后全部一起 sort 一遍,做个后缀排序就行了。

复杂度是 O(nlog2n+|Σ|!n)

wlk

题意

有一张图,每一个点有至少一条出边,每条边上有一个小写字母。有一只大象在图上走路,一开始在 1 号点,之后每一步会随机选择该点的一条出边并走过去。

将大象走过的边上的小写字母顺次相连,就构成了一个字符串。大象有两个串 ab ,如果大象走出的串包含 a 作为子串或包含 b 作为子序列,大象就会很生气,停止行走。

大象想知道在停止行走前大象期望会走几步。输入保证这个值是一个有理数,你只要输出它 mod998244353 的值即可。

数据范围

n20,|a|10,|b|50

题解

一开始看错题好久。。。后来才发现是或!

吸取教训,一定要认真读题

暴力直接 O((n|a||b|)3) 高消就行了。

发现对于第三维,要么从 i 要么从 i+1 转移过来。

那么我们第三维直接倒推,每次重新做高消就行了,复杂度就变成 O((n|a|)3|b|) 的。

cal

题意

提交答案题。给你一个长为 10000121 的数组。

乘法、快速幂运算(能做数组上的),以及加常数,和条件跳转。

需要完成 10 个任务,最小化操作次数。

题解

人类智慧造计算机题。

点太多就不全讲了。

输入一个 [0,10000120] 的整数 a ,若 a2 的倍数输出 1 ,否则输出 0

考虑 (1)a 次方就行了。。。

输入一个 [0,10000120] 的整数 a ,若 a3 的倍数输出 1 ,否则输出 0

求出 31(mod1000121) ,然后判断 27a×313a 就行了。

输入两个 [1,5000000] 的整数 ab ,输出 a+b

正解是啥二进制拆分。。直接 (1+ab)b 就行了。。

输入两个 [1,5000000] 的整数 ab ,输出这两个数的最大公约数。

利用更相减损法,如何使得复杂度正确呢?如果每次 mod2=0 ,就直接除。然后判断大小考虑把 ab 判断 3ab3a3b 就行啦(orz Great_Influence)。

3-18

gra

题意

这是一道交互题。

一个圆上有 n 个等分点。每两个点之间都有一条边,要么为白色要么为黑色。

你每次可以询问一条边的颜色,要求出一个树满足所有边同色,以及固定顶点后是一个平面图。

n1000 询问次数在 2n 内为满分。

题解

神仙做法QAQ

先找到一个点 p 使得 p1ppp+1 两条边颜色不同。

如果找不到直接把当前颜色的边当成整个联通块就行了。

然后把 p 删掉,然后把剩下的点继续当成一个联通图做上述的算法就行了。

然后求出剩下点生成树的颜色,然后由于 p 向左向右都有选择,那么直接连上对应颜色的边就行了。

不难发现只会问 2n 次。

edg

题意

定义 k 正则图,为所有点度数都为 k 的图。

给你一个联通的偶正则图,删掉其中一些边变成 2 正则图,给出一组删边方案。

n,m105

题解

注意到由于每个点度数都是偶数并且图连通,这个图存在一个欧拉回路。

  • 考虑用欧拉回路上的顺序将边定向,那么设原图为 2k -正则图,在这个新的有向图上每个点入度和出度就都是 k
  • 考虑在新图上对于每个点选取一条入边和一条出边。容易想到使用二分图匹配,把点拆成入点和出点,对于有向边 aba 的出点和 b 的入点相连,那么一种方案就对应着这个二分图上的一个完美匹配。

其实一定有解,为什么呢?考虑反证法。

由于这个有向图上每个点入度和出度都是 k ,这个二分图上每个点度数也都是 k ,所以一定存在一个完美匹配。

这是 hall 定理的一个很自然的推论,考虑左侧的x个点在右侧的临点个数,左边这些点共连到这些临点 kx 条边,那么右侧的临点个数如果小于 x ,必有点度数 >k ,矛盾。

然后用 Dinic 跑的话,复杂度是 O(mm) 的。

总结

无向图度数有时不好考虑,可以考虑定向后解决。

mie

题意

这是一道提交答案题。

你需要构造一个 n×m 的扫雷棋盘,满足 h 个限制。

限制有五种,行列限制个数,一个九宫格限制个数,行列连续段个数。

题解

随便找几个点来讲。。。

n,m300 且只有行列的和限制。

考虑建一个二分图进行费用流。左侧建 n 个点表示 n 行,如果有限制行和就连 Sx ,容量为行和,费用为 1 的边,否则就连 Sx 容量 的。

右侧类似地建 m 个点表示 m 列。中间连一些容量为 1 的边即可。

此时我们就会优先选有限制的,把有限制的先解决,然后再做没限制的,一定可以对应到合法节点。

3-20

duliu

题意

给你一个长为 n 的序列 {di}

定义一个区间的价值 val(l,r)=la,brda+db

m 个询问,每次询问 l,r,xminlabr,val(a,b)xmaxi[a,b]di

数据范围

n,m3×105

题解

考试的时候写了一个二分主席树。。还理解错题意了。。挂成sb

O(nlog2n) 的做法很多,正解是 O(nlogn) 的。

那个区间的取值其实就是 val(l,r)=2×(rl+1)×(sumrsuml1)

考虑一个询问 (L,R,X) 与一个区间 [a,b][L,R]:

  • L<a 并且 da1maxi[a,b]{di} ,那么 [a1,b] 一定优于 [a,b]
  • b<R 并且 db+1maxi[a,b]{di} ,那么 [a,b+1] 一定优于 [a,b]

所以,我们只需要考虑满足下列至少一个条件的区间 [a,b]:

  1. a=L 或者 b=R
  2. maxi[a,b]di<min(da1,db+1)

判掉无解后,我们对于第一种情况只需要二分出对于 L,R 向右向左第一个合法节点 minr(L),maxl(R)

第二类区间其实只有 O(n) 个,怎么做呢?我们考虑按权值从小到大加入,每次联通的一块就是合法的区间(可以用并查集维护)。

而在单个询问中,只需用到 a[L,maxl(R)] 并且 val(a,b)X[a,b] 。可以扫描线 + 线段树(把 Xval(a,b) 从大到小排序)。

复杂度是 O((n+m)log(n+m)) 的。

gre

题意

求出一个长为 n 恰好包含了 k 个小写字符的字典序最小的字符串满足,对于每个前后缀都有所有出现了的字符的出现次数互不相等。

n105,k26

题解

考虑 找规律 构造,一定形如:

aababacbabaa

我们定义 A=a,B=ba,C=cba, ,那么其实就是

AABBCBA

就是前面 1k1 的下降串都会出现两次,最后 k1 的下降串出现一次。然后不够前面一直补 a 肯定不劣。

为什么呢?我们可以考虑如下构造:

c b b b b aa a a a aa

我们只需要考虑相邻两个字符,保证字典序较小那个出现次数恒大于字典序较大的。

这样的话,字典序就一定是最小的,且满足每个前后缀都合法。

tetris

俄罗斯方块搜索神题,不会搜不会搜,弃疗。

3-21

Exchange

题意

有一个长为 n 的序列 {ai} 。有 m 次询问,每次询问一段区间 [l,r] 中选取一个点 x 为开头的上升序列的最大值(每次到一个更大的值一定更新序列)。

n,m1.5×106

题解

考虑每个点向右边第一个比它大的点连边,(假设 an+1= )那么就是一棵树。

询问等价于,我们问一段区间 [l,r] 构成虚树的最大深度。我们不难发现对于每个点的子树都是连续的一段。

我们考虑把所有询问按右端点排序后,我们每次加入一个点,也就是是使得子树深度 +1 ,然后查一段区间的最大值,用线段树实现即可。复杂度 O((n+m)logn)

Tree

题意

这是一道交互题。

有一颗 n 个点的树,你可以询问两个点 (x,y) 路径上包含了你给的集合 S 的多少个点,最多问 T 次,需要还原整棵树。

n1000,T1.2×104

题解

考虑定 1 号点为根,然后问出每个点的深度,逐个确定每个点 i 的父亲。

显然它父亲的深度是 depi1 ,我们二分一下它到根节点路径上经过的父亲集合就行了。

只需要 O(nlogn) 次询问,常数比较小,大约 60008000 次。

Hanoi

绝世毒瘤结论神题,弃疗。

3-23

Lemon

题意

一棵 n 个点的树,每个点有两个权值 wi,di ,可以做两个操作:

  • 给某任意点 xdx+k (只能做一次)。
  • 交换任意两个点 u,vwu,wv (不限次数)。

求出最小的 k 满足对于任意一个点 xdi 不小于子树中 wi 的最大值。无解输出 1

数据范围

n5×105,0di,wi109

题解

考场想了一个sb的 O(nlog2n) 的做法。

首先转化一下,每个点的 si 就是它到根 dimin ,然后需要满足 s,w 分别从小到大排序,diwi

具体来说就是二分一下答案,枚举给 du+k ,然后考虑更改之后影响的点,其实就是 v 到根路径上的 d 最小值为 du 这类的 v ,记 secvv 到根路径上 d 的次小值。然后变化后的值其实就是 sv=min(du+k,secv)

然后就等价于有 O(n) 个散点,和 O(n) 个区间要判断。散点直接比较即可。然后需要依次判断每段区间是否合法,这个只需要对于每个位置找出向左至少移动才合法的位置,然后用 RMQ 求一下区间最大值就能判断了。

用归并进行排序,那么瓶颈只在于求断点,那个地方我不太会做。所以只能 O(nlog2n) 了。但是加一些奇奇怪怪的优化可以跑的很快。。


正解是 O(nlogn) 的。

考虑堆存储 si ,然后每次拿最大的 wi 去匹配。然后找到第一个不合法的节点。

那么此时一定要加固了,我们肯定是加固堆中的点,并且是恰好加固到 wi ,朴素模拟是 O(n2) 的。

其实套上我之前那个判断就可以做到 O(nlogn) 了。。

cnti 表示,有多少个节点 j 满足 sjwi ,那么可行当且仅当 cntii0 。考虑用线段树上维护 cntii 的最小值,修改 si 也就是在线段树进行区间加减。

由于堆中的节点的子树互不相交,总复杂度为 O(nlogn) 的。

Invert

题意

有一个 n×n 的棋盘,其中 m 个矩形为黑色。两个人在上面博弈,每次可以将以一个白色格子为右下角的不超过 k 的正方形内所有格子反色(不能超过边界)。

不能操作者输,求先后手谁必胜。

数据范围

1kn109,m5×105

题解

显然每个黑点是独立的,我们考虑打表找出 SG 函数的规律,其实就是,设 lim 为不超过 k 的最大的 2 次幂:

SG(i,j)=min{lowbit(i),lowbit(j),lim)}

最后只需计算被矩形覆盖的所有位置的异或和,这部分可以用扫描线+线段树完成。对于每个 ii[0,29] ,用线段树维护当前所有被覆盖的纵坐标 y 中,lowbit(y)=2iy 的个数。事实上我们只关心个数的奇偶性,因此可以用一个二进制数存下信息。

具体来说其实就是把每个矩形差分后,按 x 从小到大排序,然后用线段树维护那些 y 有值区域的异或和即可,然后要把 lowbit(x) 限制进去,就需要按位讨论一下。

至于 min(lim) 可以最后考虑,具体来说就是把每个 >lim 的位强制压下来。

复杂度是 O(m(logn+logm)) 的。

Triplet

题意

这是一道交互题。

一个长为 n 的序列 {Ai} ,每次可以询问三个位置 x,y,z ,会告诉你 max{Ax,Ay,Az}+min{Ax,Ay,Az}

保证 Ai 互不相同,需要在 min{n+35,2×n} 的次数内猜出序列。

数据范围

5n104,1Ai109

题解

首先考虑 5 个数如何在 (53)=10 次内问出来。我们把所有排列全问出来,然后我们需要知道 5 个数的相对大小,我们考虑包含这个数的 4 个排列的答案和,我们从小到大排序,这个相对顺序其实就是原本的大小关系。

然后随意模拟消元解出答案即可,接下来就需要算剩下 n5 个数。

我们考虑维护三个当前已知的数 Al<Ar<Arr ,假设我们要求 Ax ,那么先问 l,x,r 如果结果不是 Al+Ar ,那么就可以直接算出来了。

是的话,那么意味着 Al<Ax<Ar ,那么我们只需要问 x,r,rr 就能算出来了。

但是这样的话,期望要问 1.5 次,最坏要 2 次。考虑优化,如果 [Al,Ar] 极短使得 Ax(Al,Ar) 就不用考虑这个条件了。那么我们每次问了之后,保留一个较短的区间即可,这样每次长度最坏变成原来的一半。

所以次数是稳定的 n+5+log2Ai 可以通过。

3-25

ds

题意

给你一个长为 n 的序列 {Ai} ,支持两个操作:

  • Ap 修改成 x
  • i=lrAi 的历史最小值。

数据范围

1n,m105,0Ai,x109

题解

考虑一下修改操作会影响哪些区间,其实就是 1ipjn

由于可以离线,先对所有询问的点建出 KDTree ,然后变成了矩形加,和询问历史最小值。

维护历史最小值只用对每个区间记录当前标记,历史最小值标记,当前值和历史最小值即可。

其实好像只要维护历史最小标记和当前标记就行了,就是到叶子的时候不下放即可。

graph

题意

对一个初始图,每次找到一个 a<b<c 的三元组满足 (a,b),(a,c) 有边,然后连接 (b,c) ,问最终得到的图的 n 种颜色染色方案数。

数据范围

n,m106

题解

考虑最后的图,不难发现对于一个点 u ,和它相邻的比它大的任意两个点颜色肯定不同。

从大到小给每个点染色,那么每个点染色的方案数就是 n 比它大的和它相邻的点的个数。乘法原理一下就可以得到答案了。问题变成怎么求点的度数。

对于最终图中 uv 有边,当且仅当在原图中存在一条 uv 的路径使得路径中间的点 <min(u,v)

按从小往大的顺序依次加点,加完点后维护当前的联通块情况以及每个联通块向外连的邻居(此时邻居的边还没有加进来)。扫到 i 时,i 所在联通块邻居个数就是 i 的度数。

实现可以用 std :: set 启发式合并 O(nlog2n) ,好写常数小。。

array

题意

对一个长度为 n 的数列 a 定义优秀度为:x1=a1,xi=xi1modai ,优秀度为 xn

给定 n 和数列 a ,问任意排列 a 的情况下最大的优秀度是多少。

数据范围

1n,ai105

题解

原题又考一遍。。。

ai 排序,如果 a1 只出现了一次,则答案就是 a1 ,否则答案一定 <a1

注意到当 x<y 时,xy 取模不会产生任何影响。用 fi 表示 i 是否能在取模过程中被达到,那么之前用到的数一定 >i ,之后的数一定不超过 i

DP 的转移式为 fi=m,kfi+km ,其中 m 是所有 >i 的模数。

注意每次只需要把 k 当成 1 转移即可,这样每个状态还是会转移到。用 std :: bitset 优化,就可以做到 O(n2ω) 了。

3-26

LCS

题意

给四个长度为 n 的序列 {ai},{bi},{ci},{di} ,求这四个序列最长公共子序列的长度。

数据范围

n104

且对于 {ai},{bi},{ci} 单个序列来说,不会有数字出现超过 2 次。

题解

由于有这个特殊条件,考虑转化一下,变成对于 ax=by=cz=dw 这类的 (x,y,z,w) 的最长上升子序列的长度。

不难发现这个元素不会超过 8n 个,然后直接用 CDQ 分治 + 二维树状数组做四维数点就行了。

复杂度是 O(nlog3n) 的,似乎 KD-TreeO(n53) 跑的飞快。。

permutation

题意

n 个数 {ai} ,求一个字典序最小的排列使得排列后相邻两个数的异或和最大值最小。

n3×105,ai109

题解

第一步都没想到,思维僵化的可怕。(退役 flag++

首先考虑最小的答案是什么,不难发现对于所有数按位从高到低第一个有 0,1 的位置一定是会出现在答案中的。

然后我们按这一位分成两个集合,然后答案其实就是两个集合中分别选一个数异或起来的最小值。

这个可以用 01Trie 查询,然后我们把可以相邻的点连边,构成一个图,我们现在就是要求一个字典序最小的哈密顿路。

但是这个图的边数可能是 O(n2) 的,其实可以不全部考虑。

在同一个集合里的数肯定会两两连边,也就是一个完全图。然后考虑把一样的数压到一起,那么每个点只会向集合外一个一个数连边。

然后我们从小到大,每次考虑贪心加入一个元素,那么我们只需要判断是否合法,如何判断呢?

  • 如果只剩当前这个集合中的点,那么合法。
  • 如果这个点是当前这个集合中的最后一个点,那么合法。
  • 如果除了这个点向外连的边还有边,那么合法。

然后这样暴力枚举是 O(n2) 的,其实有用的点不是特别多,也只有三类:

  • 跳到另外一个集合
  • 同一个集合的最小点
  • 同一个集合的次小点

为什么呢?最小点不合法的时候,可以根据前面那些条件推出次小点一定合法。

然后用 set 维护一下就行了,复杂度是 O(n(logn+logAi)) 的。

cannon

题意

平面上有 n×m 的网格,除了 (0,0) 外每个格点都有一个目标。从 y 轴正方向开始,每次看方向上有没有目标,有就打,否则顺时针旋转到第一个目标。问第 k 个打的是多少。

数据范围

n,m106,T103

题解

显然我们可以二分斜率,但是用 double 显然会挂成sb。

考虑用 Stern-Brocot Tree 实现这个过程,由于这是一个二叉搜索树,我们可以考虑在树上遍历。

然后我们就是要求在 y=abx 下面的整点数,用类欧几里得算法求直线下整点个数即可。

然后直接遍历复杂度是 O(n) 的,考虑优化,由于一些奇奇怪怪的性质,它遍历时候的拐点只有 O(logn) 个,所以我们二分拐点即可。

复杂度是 O(Tlog3n) 的,跑的很快。。

3-28

white/black

题意

写一个五子棋程序,然后按对战排名得分。

题解

???这东西还可能有题解???

tree

题意

有一棵 n 个点的带边权的以 1 号点为根的有根树,小 Z 一开始站在根,有一个宝箱位于一号点之外的某一个点。

现在小 Z 可以在树上随便走,走过一条权值为 x 的边需要花费 x 秒,请告诉小 Z 在按照最优策略走的情况下,期望多少秒来到有宝箱的节点。误差在 106 以内被认为是对的。

一条边不能被经过三次及以上。

数据范围

n100000

题解

答案乘上 n1 后就是每个点第一次访问的时间之和,所以实际上就是在每个节点确定子节点的遍历顺序使得答案最小。

那么我们设 fu 为考虑完 u 子树内的节点最小需要遍历完的时间,我们令 wvv 子树内所有边以及 vu 这条边的权值和,那么式子其实就是:

fu=maxp{ifpi+(valpiu+2j<iwpj)szpi}

我们发现其实只需要找到一个排列 p ,最小化:

iszpij<iwpj

这种最优化排列的问题,我们通常可以考虑相邻两个交换后对于答案的关系,推下式子也就是:

szawb<szbwa

的时候 ab 前面时候优。

那么每次合并的时候排下序就行了,复杂度是 O(nlogn) 的。

number

题意

数轴上有 n 个区间,第 i 个区间是 [Li,Ri] ,你可以进行不超过 k 次操作,每次操作可以选定一个区间,将其左移或右移一个单位长度。

操作完之后,求出所有区间的交,最终收益为交中的 “好数” 的个数。求最大收益。

若一个正数的十进制表示中只有 47 出现,那么这就是一个好数。比如 474,4477 是好数,475,233 则不是。

数据范围

n105,k10181LiRi1018

题解

这种sb题都没想到(退役 flag++

其实好数个数只有 219 个。。。

然后我们考虑枚举一个好数作为左端点,二分最远的好数右端点。

然后用二分端点,然后用前缀和算一下需要移动的个数就可以实现判断了。

这样是 O(219log2n) 的。

考虑把二分换成 two-pointers 就可以做到 O(219logn) 了。


__EOF__

本文作者zjp_shadow
本文链接https://www.cnblogs.com/zjp-shadow/p/10548591.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zjp_shadow  阅读(112)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示