2020牛客暑期多校训练营

2020牛客暑期多校训练营

第一场出题人:叉姐

A B-Suffix Array: 后缀数组

链接
传送门: here
题意
n ( 1 e 5 ) n(1e5) n(1e5)的字符串只包含 a b ab ab两个字母,对它的 n n n个后缀字符串按 B B B函数来排序。
字符串的 B B B函数是一个向量, b i = m i n 1 < = j < i , s [ j ] = = s [ i ] ( i − j ) bi=min_{1<=j<i,s[j]==s[i]}(i - j) bi=min1<=j<i,s[j]==s[i](ij)

思路
对于字符串的B值可以将他分成两部分求:
S=AD, 其中 A = aa…ab or bb…ba
A部分的B值为: 011…10
这是确保后缀S的D部分之前ab都出现过了,对D部分求出来的B值的顺序可以直接
参考后缀数组对整个字符串B值排序的答案。
所以我可以对每个后缀记录三个值: one, isZero, sf
one: A部分中1的个数
isZero: A部分是否有最后一个0,即是否ab都出现了,即是否后面还有值
sf: D部分在后缀数组中的rank
对上面三个值从小到大排序之后的 id 即为答案。

备注
叉姐说当只有两个字符时,有一个论文结论,对源字符串求出C值 ,
ci=min(j - i) 且 1<=i<j,s[j]==s[i],再末尾补上一个数 n+1 ,
然后对这个 C 值求后缀数组的 sa 反过来就是答案。

AC_CODE
代码地址

B Infinite Tree: 虚树+DP

链接
传送门: here
题意
m i n d i v ( x ) mindiv(x) mindiv(x) be the minimum divisor greater than 1 1 1 of n n n.
δ ( u , v ) \delta(u, v) δ(u,v) be the number of edges between vertices u u u and v v v
m = 100000 , w [ i ] < = 10000 m = 100000, w[i] <= 10000 m=100000,w[i]<=10000
ϕ \phi ϕ
m i n u ( ∑ i = 1 m w [ i ] ∗ δ ( u , i ! ) ) min_u(\sum_{i=1}^m w[i]*\delta(u, i!)) minu(i=1mw[i]δ(u,i!)), u你自己任选,求最小值

思路
建出虚树然后 dp 即可
虚树中1,2!,3!,…,n!间不会存在相邻两个点 lca 高度和 x! 的高度相同
但是会存在 x,y 的 lcadep 高度相同,他们的lca可能都是1根节点,但是肯定不会是别的点还在同一条链上,
x ! = p 1 k 1 ∗ p 2 k 2 . . . p m k m x! = p1^{k1}*p2^{k2}...pm^{km} x!=p1k1p2k2...pmkm
从1到x!的路径长度为 ∑ i = 1 m k i \sum_{i=1}^m ki i=1mki
从1到x!路径上相邻两点的倍数关系一定是km个pm, …, 直到k1个p1
x ! x! x!的深度比 ( x − 1 ) ! (x-1)! (x1)!的深度多 x x x 的素因子次数和
x ! x! x! ( x − 1 ) ! (x-1)! (x1)!的分界点一定是次数不相同的最大的素数

备注

AC_CODE
代码地址

H Minimum-cost Flow: 最小费用最大流

链接
传送门: here
题意
n = 50 , m = 100 n=50, m=100 n=50,m=100
给你一个最小费用流图,边单位流量费用 c i ci ci Q ( 100000 ) Q(100000) Q(100000)次询问,每次询问告诉你每条边的流量上限是 u v \frac uv vu(保证 ≤ 1 \le 1 1),问要从源点 1 1 1流一个单位流量到汇点 n n n的最小费用是多少。

思路
因为每条边的流量上限其实都是一样的,所以我们首先预处理,把每条边的流量扩大 v u \frac vu uv倍,这样所有流量上限都是 1 1 1,费用流每次增广的时候只会增广 1 1 1的流量,然后记录下每次增广的花费,边只有 100 100 100条,最多只会增广 100 100 100次.
询问就是暴力枚举每一条增广路径看流量和是否满足条件,若某次增广的流量多了就截断多的部分,只取到刚好我要的流量,并算贡献。
复杂度就是 O ( m ∗ q ) = 1 e 7 O(m*q) = 1e7 O(mq)=1e7刚好可以过.

比如你加个前缀和预处理,二分处理询问,这样复杂度就是 O ( q ∗ l o g ( m ) ) O(q*log(m)) O(qlog(m))
当然可以更快,你可以 O ( 1 ) O(1) O(1)算出答案来,复杂度就是 O ( q ) . O(q). O(q).

我这里算的复杂度没有把求 g c d gcd gcd算进去.

备注

AC_CODE
代码地址

I 1 or 2: 思维拆点+带花树

链接
传送门: here
题意
n = 50 , m = 100 n=50,m=100 n=50,m=100
小明要求每个点的度数为 d u [ i ] = 1 o r 2 du[i] = 1 or 2 du[i]=1or2, 问你是否存在这样一个边的子集
满足上述条件。
不存在自环,可能有重边
度数和一定要保证为偶数

思路
把一条边拆成两个点,把每个点 u u u拆成 d u [ u ] du[u] du[u]个点
e d g e − > e 1 e 2 edge ->e1 e2 edge>e1e2
x − > x 1 x -> x1 x>x1
y − > y 1 y 2 y -> y1 y2 y>y1y2
( e 1 , e 2 ) , ( x 1 , e 1 ) , ( e 2 , y 1 ) , ( e 2 , y 2 ) (e1, e2), (x1, e1), (e2, y1), (e2, y2) (e1,e2),(x1,e1),(e2,y1),(e2,y2)
再跑一般图最大匹配
看是否是完备匹配
如果存在完美匹配的话,一定可以是每条边拆成两个点分别和两个端点拆成的 d u [ i ] du[i] du[i]个点中的一个相匹配。
如果完备匹配的话,证明说有条件都满足。

备注
如果 d u [ i ] du[i] du[i]等于任意 0 0 0或者整数, 也是可以这样写的.
如果 d u [ i ] du[i] du[i]等于 0 0 0的话,相当于 i i i相邻的边拆成的两个点自己和自己相匹配.
扩展题号为HDU3551,VJUDGE上有我share的提交.

AC_CODE
代码地址


第二场出题人:高铭鸿

A All with Pairs: 建完AC自动机dfs一遍即可

链接
传送门: here
题意
n ( 1 e 5 ) , ∑ ∣ s i ∣ ≤ 1 e 6 n(1e5),\sum |s_i| \le 1e6 n(1e5),si1e6
∑ i = 1 n ∑ j = 1 n f ( s i , s j )    m o d    998244353 \sum_{i=1}^n\sum_{j=1}^nf(si,sj)\;mod\;998244353 i=1nj=1nf(si,sj)mod998244353
f ( s , t ) f(s, t) f(s,t)as the maximum i i i that satisfy s 1 … i = t ∣ t ∣ − i + 1 … ∣ t ∣ s_{1\dots i} = t_{|t|-i+1 \dots |t|} s1i=tti+1t

思路
为字符串 u u u 找其他字符串的前缀和 u u u 的后缀所产生的贡献。每个节点保存字典树子树中 e n d    n o d e end\;node endnode信息。遍历 f a i l fail fail连接树,前面遍历过的节点都是我的后缀为每个字符串记录一下遍历到当前节点匹配的最长前缀即可。回溯时记得还原。

备注

AC_CODE
代码地址

G Greater and Greater: bitset

链接
传送门: here
题意
n ( 150000 ) , m ( 40000 ) , 1 ≤ a i , b i ≤ 1 e 9 n(150000),m(40000),1\le a_i,b_i\le 1e9 n(150000),m(40000),1ai,bi1e9, 问 a [ ] a[] a[]有多少个子数组 S S S
满足 ∀ i ∈ { 1 , . . . , m } , S i ≥ b i . \forall i\in\{1,...,m\},S_i\ge b_i. i{1,...,m},Sibi.
思路
W W W机器位长
法1:
首先对 m m m种权值建一个大小为 n n n b i t s e t    S i bitset\;S_i bitsetSi, S i [ j ] = 1 S_i[j]=1 Si[j]=1当且仅当 a [ j ] ≥ b [ i ] a[j]\ge b[i] a[j]b[i],
这个可以 O ( n m / W ) O(nm/W) O(nm/W)预处理,再依次枚举每个 S i S_i Si a n s & = ( S i > > i ) ans \&= (S_i>>i) ans&=(Si>>i),答案是 a n s . c o u n t ( ) ans.count() ans.count()
然后你可以发现利用 m e r g e _ s o r t merge\_sort merge_sort过程滚动处理优化内存,这样只需要开两个 b i t s e t bitset bitset即可。
法2:
n n n种权值建一个大小为 m m m b i t s e t    S i bitset\;S_i bitsetSi, S i [ j ] = 1 S_i[j]=1 Si[j]=1当且仅当 a i ≥ b j a_i\ge b_j aibj,然后
你会发现其实本质只有 m m m个不同的 b i t s e t bitset bitset,利用 m e r g e _ s o r t merge\_sort merge_sort优化预处理的时间复杂度。
从后往前枚举,统计合法的长度为 m m m的后续, c u r & = ( c u r > > 1 ∣ I m ) & S i cur\&=(cur>>1|Im)\&S_i cur&=(cur>>1Im)&Si,答案是 c u r [ 0 ] cur[0] cur[0]
备注
CF914F
AC_CODE
代码地址

H Happy Triangle: 动态开点线段树

链接
传送门: here
题意

  1. 插入一个x
  2. 删除一个x
  3. 询问是否有两个数可以和x形成三角形

思路
动态开点权值线段树
对于查询只有三种情况,x是三边之中最大的,x是三边之中第二大的,x是三边之中最小的
备注

AC_CODE
代码地址

J Just Shuffle: 置换群

链接
here
题意
最开始 a r [ i ] = i ar[i] = i ar[i]=i, 要你求一个 n n n的排列 p [ ] p[] p[], 满足做 m m m(大质数)次
n e w _ a r [ i ] = p [ a r [ i ] ] new\_ar[i]=p[ar[i]] new_ar[i]=p[ar[i]]后的 n e w _ a r [ ] new\_ar[] new_ar[] 数组为输入给定的 a r r [ ] arr[] arr[]数组。
思路
首先你把 i − > a r [ i ] i->ar[i] i>ar[i]都首尾相连列出来,表示 i i i变换 m m m次后变成 a r [ i ] ar[i] ar[i]
它肯定会形成若干个环,环的大小假设是 x x x,那么也就是 x x x个数字相互转换,一定
会成大小为 x x x的环因为 m m m是大于 x x x的大质数,那么一定有
k ∗ m % x ∣ 0 ≤ k < x = k ∣ 0 ≤ k < x {k*m\%x|0\le k \lt x} = {k|0\le k\lt x} km%x0k<x=k0k<x.
我们模拟走 x x x m m m步,把环之间相互直接的变换模拟出来,然后还原 p p p数组即可。
复杂度 O ( n ) O(n) O(n)
备注
ICPC NEAU Programming Contest 2020~~ E. 随便置换
AC_CODE
代码地址


第三场出题人:dreamoon


第四场出题人:蒋世彪


第五场出题人:不朽之夜

B Graph: 字典树

链接
传送门: here
题意
xor最小生成树
Boruvka算法
任意两点之间的边权的路径边权值的异或和,求mst。
思路
求1到任意点的路径权值异或和,问题转化为任意两点之间的边权等于
两点点权异或和,xor mst裸题。
做法1:启发式合并
920 ms
点权做trie树,遍历整个trie树,若某点左右儿子内都有权值,则遍历size小的
一方,再另一方查询最小异或和。
复杂度: O ( n ∗ l o g ( n ) ∗ 30 ) O(n*log(n)*30) O(nlog(n)30)

做法2:逐位合并贪心
561 ms
把点权从小到大排序,然后从最高位开始,按照每一位的01状态分割成两边(同时再递归下去),
对于这一层遍历该为为0的一边的点权建立trie树,再遍历另一边点权求min xor sum。
注意若从小到大排序则必须从最高为开始求解。
复杂度: O ( n ∗ l o g ( n ) ∗ l o g ( n ) ) O(n*log(n)*log(n)) O(nlog(n)log(n))

做法3:暴搜贪心+玄学难卡
623 ms 这个有点玄学复杂度,而且很难卡, hdu6625
点权做trie树,遍历整个trie树,若某点左右儿子内都有权值,则左右儿子
两棵字典树同时往下走,求两棵字典树最小xor sum。
复杂度: O ( 能 过 ) O(能过) O()
备注
听说dreamoon出hdu6625的灵感就是来源本题cf888G
AC_CODE
代码地址


第六场出题人:李泽仁

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值