多校训练赛题解 第四场 2017 Multi-University Training Contest 4 solutions BY 陈松杨

2017 Multi-University Training Contest 4 solutions BY 陈松杨

1001. Big Integer

如果知道k−1k-1k1个数的个数c1,c2,...,ck−1c_1,c_2,...,c_{k-1}c1,c2,...,ck1,那么方案数就是:

(∑i=1k−1ci)!∏i=1k−1ci!\frac{\left(\sum\limits_{i=1}^{k-1} c_i\right)!}{\prod\limits_{i=1}^{k-1}c_i!}i=1k1ci!(i=1k1ci)!

构造多项式fi(x)=∑j=0ngi,jj!xjf_i(x)=\sum\limits_{j=0}^n \frac{g_{i,j}}{j!}x^jfi(x)=j=0nj!gi,jxj,则将这k−1k-1k1个多项式乘起来之后,每一项乘以i!i!i!即可得到答案,可以用NTT在O(nk2log(nk))O(nk^2\log(nk))O(nk2log(nk))的时间内预处理出初始答案。

注意到我们只关心每个时刻答案的和,故可以在DFT意义下直接累加答案,最后再将结果IDFT回来。

对于单点修改操作,可以看成是给某个多项式叠加上一个只有一项系数不为000的多项式,观察NTT的公式:

yn=∑i=0d−1xi×(gP−1d)inmodPy_n=\sum_{i=0}^{d-1} x_i\times\left(g^\frac{P-1}{d}\right)^{in}\bmod Pyn=i=0d1xi×(gdP1)inmodP

那么它在DFT后的结果是一个等比数列,故直接对原始多项式叠加一个等比数列即可完成修改。

对于叠加多项式,直接O(k)O(k)O(k)重新计算乘积是不可取的,正确方法是对于每一项记录非000的乘积以及000的个数,单次修改时间复杂度为O(1)O(1)O(1)。每次操作的时间复杂度为O(nk)O(nk)O(nk)

总时间复杂度O(nk2log(nk)+mnk)O(nk^2\log(nk)+mnk)O(nk2log(nk)+mnk)

1002. Classic Quotation

首先通过KMP算法预处理出TTTnextnextnext数组,设:

prefipref_iprefi表示SSS的前缀iiiTTT进行KMP后KMP的指针到达了哪里。

pregipreg_ipregi表示SSS的前缀iiiTTT出现的次数。

sufi,jsuf_{i,j}sufi,j表示从SSS的后缀iii,从jjj指针开始KMP,能匹配多少个TTT

那么前缀iii拼接上后缀jjjTTT的个数为pregi+sufj,prefipreg_i+suf_{j,pref_i}pregi+sufj,prefi

pregpregpregpregpregpreg的前缀和,sufsufsufsufsufsuf的后缀和,si,js_{i,j}si,j表示iii前面中prefprefprefjjj的个数,那么对于询问L,RL,RL,R

ans=∑i=1L∑j=Rnpregi+sufj,prefi=(n−R+1)pregL+∑i=0m−1sL,i×sufR,ians=\sum_{i=1}^L\sum_{j=R}^n preg_i+suf_{j,pref_i}=(n-R+1)preg_L+\sum_{i=0}^{m-1}s_{L,i}\times suf_{R,i}ans=i=1Lj=Rnpregi+sufj,prefi=(nR+1)pregL+i=0m1sL,i×sufR,i

以上所有数组均可以使用KMP和递推求出,时间复杂度O((n+k)m)O((n+k)m)O((n+k)m)

1003. Counting Divisors

n=p1c1p2c2...pmcmn=p_1^{c_1}p_2^{c_2}...p_m^{c_m}n=p1c1p2c2...pmcm,则d(nk)=(kc1+1)(kc2+1)...(kcm+1)d(n^k)=(kc_1+1)(kc_2+1)...(kc_m+1)d(nk)=(kc1+1)(kc2+1)...(kcm+1)

枚举不超过r\sqrt{r}r的所有质数ppp,再枚举区间[l,r][l,r][l,r]中所有ppp的倍数,将其分解质因数,最后剩下的部分就是超过r\sqrt{r}r的质数,只可能是000个或111个。

时间复杂度O(r+(r−l+1)loglog(r−l+1))O(\sqrt{r}+(r-l+1)\log\log(r-l+1))O(r+(rl+1)loglog(rl+1))

1004. Dirt Ratio

二分答案midmidmid,检验是否存在一个区间满足size(l,r)r−l+1≤mid\frac{size(l,r)}{r-l+1}\leq midrl+1size(l,r)mid,也就是size(l,r)+mid×l≤mid×(r+1)size(l,r)+mid\times l\leq mid\times (r+1)size(l,r)+mid×lmid×(r+1)

从左往右枚举每个位置作为rrr,当rrr变化为r+1r+1r+1时,对sizesizesize的影响是一段区间加111,线段树维护区间最小值即可。

时间复杂度O(nlognlogw)O(n\log n\log w)O(nlognlogw)

1005. Lazy Running

w=min(d1,2,d2,3)w=\min(d_{1,2},d_{2,3})w=min(d1,2,d2,3),那么对于每一种方案,均可以通过往返跑www这条边使得距离增加2w2w2w。也就是说,如果存在距离为kkk的方案,那么必然存在距离为k+2wk+2wk+2w的方案。

disi,jdis_{i,j}disi,j表示从起点出发到达iii,距离模2w2w2wjjj时的最短路,那么根据dis2,jdis_{2,j}dis2,j解不等式即可得到最优路线。

时间复杂度O(wlogw)O(w\log w)O(wlogw)

1006. Logical Chain

对于每个询问,求出强连通分量,那么一个点数为ttt的强连通分量对答案的贡献为t(t−1)2\frac{t(t-1)}{2}2t(t1)

利用Kosaraju算法,只需要在正反图各做一次DFS即可求出强连通分量。面对稠密图,Kosaraju算法的瓶颈在于寻找与点xxx相连且未访问过的点。考虑用bitset来保存边表gxg_xgx,以及未访问过的点集SSS,那么只需要取出gx&Sg_x\&Sgx&S内的所有111即可在O(n264)O(\frac{n^2}{64})O(64n2)的时间内求出强连通分量。

时间复杂度O(mn264)O(\frac{mn^2}{64})O(64mn2)

1007. Matching In Multiplication

首先如果一个点的度数为111,那么它的匹配方案是固定的,继而我们可以去掉这一对点。通过拓扑我们可以不断去掉所有度数为111的点。

那么剩下的图中左右各有mmm个点,每个点度数都不小于222,且左边每个点度数都是222,而右侧总度数是2m2m2m,因此右侧只能是每个点度数都是222。这说明这个图每个连通块是个环,在环上间隔着取即可,一共两种方案。

时间复杂度O(n)O(n)O(n)

1008. Phone Call

不难发现这个过程就是Prim算法求最小生成树的过程,用Kruskal算法同样正确。

将所有线路按代价从小到大排序,对于每条线路(a,b,c,d)(a,b,c,d)(a,b,c,d),首先把aaabbb路径上的点都合并到LCA,再把cccddd路径上的点都合并到LCA,最后再把两个LCA合并即可。

fif_ifi表示iii点往上深度最大的一个可能不是和iii在同一个连通块的祖先,每次沿着fff跳即可。用路径压缩的并查集维护这个fff即可得到优秀的复杂度。

时间复杂度O(mlogm)O(m\log m)O(mlogm)

1009. Questionnaire

m=2m=2m=2,必然存在一组可行解。

1010. Security Check

fi,jf_{i,j}fi,j表示仅考虑a[1..i]a[1..i]a[1..i]b[1..j]b[1..j]b[1..j]时,最少需要多少时间。

∣ai−bj∣>k|a_i-b_j|>kaibj>k,则fi,j=fi−1,j−1+1f_{i,j}=f_{i-1,j-1}+1fi,j=fi1,j1+1,否则fi,j=min(fi−1,j,fi,j−1)+1f_{i,j}=\min(f_{i-1,j},f_{i,j-1})+1fi,j=min(fi1,j,fi,j1)+1

注意到后者只有O(nk)O(nk)O(nk)个,可以暴力DP,前者可以通过二分找到最大的ttt,满足i,ji,ji,j往前ttt个均不冲突,然后再从某个后者状态转移过来。

时间复杂度O(nklogn)O(nk\log n)O(nklogn)

1011. Time To Get Up

按题意模拟即可。

1012. Wavel Sequence

fi,j,kf_{i,j,k}fi,j,k表示仅考虑a[1..i]a[1..i]a[1..i]b[1..j]b[1..j]b[1..j],选择的两个子序列结尾分别是aia_iaibjb_jbj,且上升下降状态是kkk 时的方案数,则fi,j,k=∑fx,y,1−kf_{i,j,k}=\sum f_{x,y,1-k}fi,j,k=fx,y,1k,其中x<i,y<jx<i,y<jx<i,y<j。暴力转移的时间复杂度为O(n4)O(n^4)O(n4),不能接受。

考虑将枚举决策点x,yx,yx,y的过程也DP掉。设gi,y,kg_{i,y,k}gi,y,k表示从某个fx,y,kf_{x,y,k}fx,y,k作为决策点出发,当前要更新的是iii的方案数,hi,j,kh_{i,j,k}hi,j,k表示从某个fx,y,kf_{x,y,k}fx,y,k作为决策点出发,已经经历了ggg的枚举,当前要更新的是jjj的方案数。转移则是要么开始更新,要么将iii或者jjj继续枚举到i+1i+1i+1以及j+1j+1j+1。因为每次只有一个变量在动,因此另一个变量恰好可以表示上一个位置的值,可以很方便地判断是否满足上升和下降。

时间复杂度O(n2)O(n^2)O(n2)

1013. Yuno And Claris

先考虑如何求区间第kkk小值。对序列和权值都进行分块,设bi,jb_{i,j}bi,j表示前jjj块中权值在iii块内的数字个数,ci,jc_{i,j}ci,j表示前jjj块中数字iii的出现次数。那么对于一个询问[l,r][l,r][l,r],首先将零碎部分的贡献加入到临时数组tbtbtbtctctc中,然后枚举答案位于哪一块,确定位于哪一块之后再暴力枚举答案即可在O(n)O(\sqrt{n})O(n)的时间内求出区间第kkk小值。

接着考虑如何实现区间[l,r][l,r][l,r]xxx变成yyy的功能。显然对于零碎的两块,可以直接暴力重构整块。对于中间的每个整块,如果某一块不含xxx,那么无视这一块;否则如果这一块不含yyy,那么只需要将xxx映射成yyy;否则这一块既有xxx又有yyy,这意味着xxxyyy之间发生了合并,不妨直接暴力重构整块。因为有ccc数组,我们可以在O(1)O(1)O(1)的时间内知道某一块是否有某个数。

考虑什么情况下会发生重构,也就是一个块内发生了一次合并的时候。一开始长度为nnn的序列会提供O(n)O(n)O(n)次合并的机会,而每次修改会对零碎的两块各提供一次机会,故总合并次数不超过O(n+m)O(n+m)O(n+m),因此当发生合并时直接重构并不会影响复杂度。

那么现在每块中的转换情况只可能是一条条互不相交的链,只需要记录每个初值转换后是什么,以及每个现值对应哪个初值即可。遇到查询的时候,我们需要知道零碎部分每个位置的值,不妨直接重构那两块,然后遍历一遍原数组aaa即可得到每个位置的值。

在修改的时候,还需要同步维护bbbccc数组,因为只涉及两个权值,因此暴力修改jjj这一维也是可以承受的。

总时间复杂度O((n+m)n)O((n+m)\sqrt{n})O((n+m)n)

本条目发布于 2017年8月3日。属于 未分类分类。 作者是sensible
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值