Chelly个人训练

Todolist

arc100F


7.1

  • Atcoder Regular Contest 100 1/4
  • Codeforces #493 div 2 4/5

7.2

  • arc100D:枚举中间那一刀,然后左边两个部分各自均匀切一刀。
  • arc100E:想要求\(max(A_i+A_j) (i\ or \ j=k)\),然后根据前缀搞,但这个很困难,无法求解。考虑求\(max(A_i+A_j) (i \ or \ j\subseteq k)\),这个是满足\(i \ or \ j <= k\)的限制的,可以用dp搞。
  • cf997C:容斥原理,化简式子后发现是两个\(\sum\),里面有两个组合数形式,可以考虑枚举一维,另一维用二项式定理化简。

7.3

  • cf997D:树上长度为k的环个数计数。
  • cf997E:枚举右端点,左端点到当前右端点的答案用线段树维护。由于问题的特殊性,维护区间最小值和最小值个数。需要维护区间历史答案和,额外用一个lazy标记就行了。

7.4

  • cf1000F:将询问按照右端点排序,枚举右端点r,对于固定的r,用线段树维护前面每个位置的pre[i],对于询问[l,r],就是要找[l,r]中的最小值,当然还有一个suf[i]>r的条件,这个条件只需要每次新来一个r,把pre[r]的位置的权值赋为inf即可。如果要求在线,那可以用主席树。
  • cf1000G:树dp一下就好。

7.5

  • cf995C:有一个结论是任意3个长度<=r的向量,必可以挑出2个向量通过变换方向组合成一个长度<=r的向量,所以就可以对原来的一直操作缩小规模,用一个二叉树来模拟。
  • cf995D:通过归纳法可以得出答案就是所有f的平均数。
  • cf995E:考虑到图比较随机,所以实际上步数不会很多(实际上最多40),那就可以双向BFS解决了。
  • cf995F:答案是关于D的次数最高为n的多项式,所以可以先做一个O(n2)的dp,然后在D的取值直接插值就行。也可以dp来处理,我们关心的只是树里面不同权值的个数,假设g(x)表示树里面权值个数为x个的时候树的形态数,那么总方案数肯定是ΣC(D,x)g(x),问题是如何求g。我们考虑dp[i]表示树中最大值为i的方案数(这显然O(n2)的DP可以做出),一定有dp[i]=ΣC(i,j)*g[j],反演求即可。

7.6

  • Wannafly挑战赛19 3/6

7.7

  • CodeM2018复赛 2/6

7.9

  • Wannafly挑战赛19 D:一定是固定一个回文子串,然后把一边砍掉,一边翻过去一部分,用manacher辅助计算就行。
  • Wannafly挑战赛19 E:BFS跑出两个数字之间最少需要多少次变换,然后连边跑费用流
  • Wannafly挑战赛19 F:求个前缀和,然后把每一位看作一个26元组,对于一个询问[l,r]就是问[l,r]里有多少个pair是相同的,直接莫队算法就行了。

7.10

  • CodeM2018 复赛 C:考虑给每个点赋值0/1,边权定义为两个点的权值的异或。若每条边都是-1,那么答案显然是每个连通块点的个数的2次幂乘积。对于已经确定的那些边权,先dfs判断是否有矛盾,若有则输出0。否则我们考虑一个由确定边组成的连通块,那么给定了一个点的确切权,剩下的也已经确定了,所以把这个连通块从答案里除掉就行了。

7.11

  • CodeM2018 复赛 E:考虑把每一个点对抽象成平面上的点,那么就相当于求矩形面积并。
  • CodeM2018 复赛 D:考虑二分答案,那么每个位置就对应了一个区间,我们把上界做一个凸包,若所有下界都在凸包上面则可以减少二分的答案,否则要增加二分的答案,但此题可以有分数,所以二分得不到正确结果。我们再分析一下二分的过程,发现其实凸包的形状是一样的,不同的mid只是带来不同的平移量,所以我们可以对于最初的点求一个凸包,然后求出点到对应凸包点距离的最大值,把它除以2就是答案。

7.12

  • CodeM2018 初赛A轮 D:考虑prim算法,从一个关键点开始BFS,遇到第一个关键点(则这一定是根据prim算法加入进去的边),然后把这个点的距离设为0,丢到priority_queue里继续扩展。

7.13

  • Codeforces #497 div 2 3/5

7.14

  • Codeforces edu47 6/7

7.26

  • Codeforces #499 div 2 3/6

7.27

  • CF1011C:修改了下实数二分的写法

  • CF1011E:把对k取模也加了进去,fix了一下

  • CF1010D:从上往下考虑每个门,考虑如果当前门的值需要改变,那么左右两个孩子哪个门的值需要改变,就这样dfs,分情况讨论即可。


8.17

  • 牛客143B:\(x^2-dy^2=k^2\)的pell方程了解一下。
  • 牛客143H:预处理f(i)表示以i为开头的递增子序列个数,然后逐位确定。

8.18

  • 牛客144J:随机两个正整数,互质的概率是\(\frac{6}{\pi ^2}\),所以我们可以把前100大的拿出来跑暴力

8.19

  • 牛客144I:把区间按照l升序排序,然后用线段树维护一段的r最大值,根据线段树去删除,删除一个位置的时间是\(O(logn)\),所以均摊时间是\(O(nlogn)\)

8.20

  • 牛客144G:s和t之间的最小割集一定是一个团和一个孤立点,设\(d[i]\)表示树上i点到其它所有点的距离和,那么\(maxflow(s,t)=min(d[s],d[t])\)。于是我们可以将\(d[i]\)数组排个序,然后算总贡献。\(d[i]\)用树形dp求即可。

8.21

  • 牛客144F:在考虑一个点应该放哪个表达式的时候,我们只关心lson和rson的值取0/1的情况数,对于一个确定的表达式,我们肯定希望一个lson中0/1的数量最多,rson同理,于是我们令dp[i][0/1]表示第i个点最多能有多少情况取0,最多能有多少情况取1,dp[i][0/1]的值一定由dp[lson][0/1]和dp[rson][0/1]转移过来。这样做一次树dp是O(n)的,但注意要使用高精度,因为每个点的高精度的位数是和子树大小同阶,所以这相当于是一个背包,所以复杂度是\(O(n^2)\)的。

  • 牛客144B:传送门


8.22

  • 牛客144E:考虑单独一个字符,至多分裂10秒就能够到达目标串T的长度,我们先考虑答案<=10秒的情况。我们可以建出T的自动机,然后可以预处理出f[i][j][k]表示字符i初始从T自动机的k状态进去,经过j秒的分裂,会从哪个状态出来。这样就可以轻松知道一个字符在10秒内能否搞出T,然后我们也就知道了初始字符串S能否在10秒内搞出T。接下来考虑答案大于10秒的情况,我们从T第一次出现的位置开始回溯,最终一定可以缩成1个字符或者2个字符(一个提供后缀,一个提供前缀),要注意这2个字符或者1个字符可能不会出现在初始串中,而出现在10s内的生成串中,所以我们要BFS一遍,求出每个字符/字符对第一次出现的时间。最后再枚举字符对即可。

  • 牛客145C:考虑到\(3^{18}\)并没有超时太多,可以预处理出最后4次的结果。时间复杂度是\(O(2^43^4+3^{14})\)


8.23

  • 牛客145F:考虑枚举d,算满足mindiff>=d的所有集合的maxdiff的和。还需要枚举集合里的元素个数k,一个集合对答案的贡献是\(a_k-a_1\),分开来利用组合数计算。需要知道带权的杨辉三角对角线的和如何计算。

8.24

  • 牛客145I:对于一个树而言直径有很多但重心只有一个,考虑计算枚举每个点作为重心的答案,显然考虑能否用点分治。以某个点u为重心的直径为D的树要怎么计数呢?首先要满足至少有两个离它深度为D/2的点分布在不同的子树,然后剩下深度<D/2的点随便取不取。这样我们需要维护两个东西,一个是<D/2的点的总数,一个是从某个分支出发,有多少个深度恰好是D/2的点,这个用一个map即可。注意到D要讨论奇数和偶数情况很复杂,可以考虑在原树中的每条边之间添加上额外的点,那么就只要统计偶直径就行了。时间复杂度\(O(n\log n)\)

8.25

  • 牛客146H:将问题转换成,最少选取多少个数字使得它们的异或值为给定值x。最多只要选取20个,我们可以考虑dp[i][x]表示至多选i个数字能否凑成数字x。那么每步转移就是给异或卷积,可以用FWT优化。在每次循环里,实际上只是关心一个位置x的点值是否为0,我们可以利用FWT(A)函数的定义来\(O(n)\)求解,所以时间复杂度是\(O(x \log x)\)的。

8.26

  • 牛客146B:对于一个合法方案,一定可以分成\(n_1+n_2\)的形式,即左下角一个\(n_1\)方阵,右上角一个\(n_2\)方阵,或者左上角一个\(n_1\)方阵,右下角一个\(n_2\)方阵。我们称前面为A类,后面为B类,显然A类和B类的数量是一致的。我们设\(g(i)\)表示\(i \times i\)的方阵,有多少个A类方案,\(f(i)\)表示\(i \times i\)的方阵总方案是多少。显然有\(f(1)=g(1)=1,f(i)=2g(i) \ (i>=2)\)。考虑递推求解\(g(i)\),对于一个A类方案,我们一定可以找到一个最小的\(n_1\),使得每个方案只被统计一次。那么有\(g(n)=\sum_{i=1}^{n-1} g(i) \times f(n-i)\),继续化简有\(f(n)=f(n-1)+\sum_{i=1}^{n-1} f(i) \times f(n-i)\)。这个用cdq分治+NTT处理即可。

  • 牛客146C:可以用树形DP求出以点u作为根的子树向下的贡献,以点u向上的贡献。然后再用树形DP统计出以u为根的连通块的总贡献。题解给出了一个更妙的思路,考虑枚举路径集合,算有多少连通块满足要求,容易发现若固定一个路径集合,那么满足条件的连通块一定就是路经集合分割而成的连通块数量,这个等于白点数-两端都是白点的边数。于是可以两部分分开计数,前者就是相当于统计不经过某个点的路径集合数量,后者是统计不经过某条边的两个点的路径集合的数量,都可以树形DP完成。


8.27

  • 牛客146I:找到第一个不一样的最高位pos,把数字分成两个集合A和B。A中数字pos位为0,B中数字pos位为1。显然我们可以利用01Trie得到答案ans,接下来主要考虑方案的选择。我们可以把这些数字看成一个二分图,左边点集互相有边相连,右边点集互相有边相连,然后对于那些异或结果是ans的点对,我们从A向B连一条边,我们需要找的就是一个字典序最小的哈密顿路。我们可以贪心的从高到低逐位确定,假设上次选择的点是u,它所在的集合在c。那么接下来我们要么在c集合里找一个点,要么在u相连的另一个集合的点里寻找一个点,这些都可以用数据结构来维护。具体来说,用set维护点集中剩余的点,用mpa<int,priority_queue>维护一个点相连的另一个集合里的点。

  • 牛客146J:固定一个n,那么生成函数就是\((1+x)^n\),所以原问题的生成函数就是\(F(x)=(1+x)^0+(1+x)^2+(1+x)^4+...=\frac{(x+1)^{n+2}-1}{(x+1)^2-1}\),我们所要求的就是\(\sum_{i=0}^{m} [i=0 \mod 2] [x^i] F(x)\)。把F(x)化简一下,可以得到\(F(x) \times (x+2)=\sum_{i=0}^{n-1}\binom{n}{i+1}x^i\)。设F(x)里\(x^i\)前的系数是\(b_i\)根据这个式子,我们可以发现\(b_0和b_{n-2}\)是确定的,其余的\(b_i\)可以由\(b_{i-1}\)或者\(b_{i+1}\)递推得到。那显然我们递推出前M项,问题就解决了。但关键是是模数是偶数的时候,可能会导致递推式子里的\(\frac{1}{2}\)没有逆元。我们可以这样来,将\(mod=s \times 2^t\),分别求出模s和模\(2^t\)的值,然后CRT合并起来。s一定和2互质,所以一定就有逆元了,可以递推了。关键就是如何求模\(2^t\)的结果。考虑倒推,有\(b_i=\sum_{j>=i+2} (-2)^{j-(i+2)}a_j\),当\(j-(i+2)>=t\) 的时候,显然贡献为0,所以这个j顶多枚举t项。整个时间复杂度是\(O(m \log mod)\)的。这个问题需要会在\(O(n \log mod)\)的时间内求出\(\binom{m}{0},\binom{m}{1},...,\binom{m}{n}\)


8.30

  • hdu6064:BEST theorem定理的应用。注意这里是固定了起点,所以欧拉回路的数目需要乘上\(deg(1)\)。同时,这里将重边看作相同的了,所以方案要除以每个重边的数目的阶乘。

9.7

  • Codeforces Edu 50 4/7

9.9

  • CF1036F:莫比乌斯反演。比较坑的地方在于求i次方根如果直接用\(pow\)精度会不够,需要对于\(i=3~60\)的先预处理打表,询问在其中二分。

9.13

  • hdu6356:将ST表倒过来。

  • hdu6357:考虑反转值域,01...xy(y-1)....xy(y+1)...9*,然后dp匹配模式串。


9.14

  • hdu6352:分圆多项式用来因式分解。

9.17

  • hdu6353:点分树。对于点分树上每一个节点u,维护点分治过程中u对应的那坨树到u的距离关系,然后求个前缀和。对于一个询问,在点分树上暴力爬就行,但注意要对答案容斥,所以还需要维护点分治过程中u对应的那坨树到last[u]的距离关系。(last[u]是点分树上u的父亲节点)

9.18

  • hdu6360:旋转规则参照正十二面体,可以列出四种置换群对应的置换个数,根据对称性算出循环个数。然后dp[i][j]表示用了前i个颜色涂了前j个循环的方案数,转移就枚举第i种颜色涂几个循环即可。

9.24

  • Codevs 3160:广义后缀自动机。统计每个点表示字符串在哪些字符串里出现过。

  • bzoj3238:后缀树。先考虑利用SAM建出后缀树,对于两个end节点,它们的lcp就是后缀树上的lca的深度(也就是lca的maxlen)。于是我们可以考虑树形DP,枚举每个树上点作为lca,统计这种情况下的答案。


9.25

  • bzoj3998:经典问题,利用SAM求第k小子串。考虑先拓扑一下,把SAM上每个节点向后能走出多少个子串求出来,然后就是从0节点开始从小到大尝试分支。

  • bzoj3676:回文树模板题。

  • bzoj4199:建出后缀树后树dp即可,注意权值有负数,所以记录子树内最大和最小值。

  • bzoj4310:考虑先二分一个mid,将字典序第mid小的字符串作为答案(可以用SA或者SAM),然后来判定是否可行。注意到分成的那些段中,字典序最大的一定是某个后缀,所以我们可以从后向前贪心,每次新加一个位置i就是新加一个 后缀,主要就是比较这个后缀与我们第mid小的字符串的大小关系。这个可以利用后缀数组求出它们的lcp来辅助判断。

  • bzoj4566:广义后缀自动机模板题。当然你需要正确地建出广义后缀自动机。


9.29

  • bzoj2780:建立广义后缀自动机。在建立第i个单词的过程中,如果新建了一个节点z,那么从z开始跳parent链,给链上的节点都赋上当前单词的颜色,最后对于每个询问就相当于统计自动机上某个点被染颜色的个数。可以用id[u]表示当前节点被染的颜色来辅助求解,可以感性理解一下,这个时间复杂度很对……

  • ARC103C:奇偶分开求出现颜色的最多和次多,最后讨论一下即可。

  • ARC103D(small case):容易发现询问点与原点的曼哈顿距离必须奇偶性都相同,然后只需要定每条机械臂长度为1就可以搞一搞了。

  • ARC103E:若有解,必须要满足:S[i]=S[n-i],S[1]=1,S[n]=0,然后根据S序列,在之前的节点基础上建立一个父亲,用额外的单点来填充size,构造树即可。


10.1

  • bzoj3277:类似bzoj2780,建出后缀自动机,求出每个点表示的子串在多少个字符串中出现。该问题要求相同的字符串不同位置算多个,最容易想到的就是求出所有点在每个颜色的下的endpos,但这样时间复杂度十分爆炸。把每个串作为一个询问串,考虑其每个前缀i有多少个后缀是满足条件的,这等价于先找出在后缀自动机上该串前缀i的终结节点,然后跳parent链,看有多少个节点的cnt>=k。这样时间复杂度也是不对的。所以可以先按照拓扑序dp一下,得到每个点到root的链上的点的权值和,这样复杂度就是线性的了。

  • bzoj3926:注意到叶子节点个数<=20,那么把每个叶子节点提起来作为根,得到就是一个Trie。所以本质上就是把这20个Trie对应的广义后缀自动机建出来就行了。

  • bzoj2806:先二分一个L,然后可以dp求出最长匹配多少位置。\(dp(i)\)表示前面i个位置最长能被匹配多少,那么有\(dp(i)=max(dp(j)+i-j) i-j>=L 且 s[j..i]是某个子串\),我们可以提前预处理出mx[i]表示s[1..i]中最长的作为子串出现的后缀,然后就是一个单调队列优化DP。至于怎么求这个mx[i],就是从前往后一直匹配维护一个cur,表示当前s[1..i]的最长后缀的长度为cur,如果从当前自动机节点有一个s[i+1]的转移,那么就转移过去并且cur+=1,否则就顺着slink跳直到有这样的转移的节点u',cur=maxlen[u']+1。

  • HackerRank special-substrings:先把问题变成“一个字符串有多少个本质不同的子串可以作为它回文子串的前缀”。我们可以先建出后缀自动机,然后对于每个本质不同的回文子串在自动机上更新答案。具体的,用回文树跑出以节点i为后缀的新增回文串,设其为s[j..i],长度为len,那么我们从代表后缀S[j]的后缀自动机节点u开始,一直向上跳slink链,若某个点maxlen<=len,那么这个点可以被完全覆盖,如果minlen<=len<=maxlen,则部分覆盖,当然直接跳链会T,可以考虑倍增跳。因为这里是离线,所以跳的时候就要注意答案的更新。时间复杂度\(O(nlogn)\)

  • bzoj1396:首先跑后缀自动机,挑出那些出现一次的位置,记下该点的suf。设点u对应的字符串出现1次,u点表示的终结位置是i,那么有[i-minlen[u]+1,i]之内对i-minlen[u]+1取min,[i-maxlen[i]+1,i-minlen[i]+1]之内对i-j+1取min,用两个线段树打标记即可。

  • bzoj4516:字符集比较大,用map即可。

  • hihocoder 1466:建两个后缀自动机,跑出sg函数。然后就是个逐步确定问题了,这里要涉及到两个的逐步确定,写的十分自闭。

  • hihocoder 1465:很容易想到把询问串T接一下,然后求每个前缀i的最大出现后缀,找到以i为后缀的包含长度n的节点u(需要跳slink),然后给这个节点打上标记。注意可能会出现循环同构,所以如果某个节点之前被打上了标记,那么这次就不累加结果。


10.2

  • ARC103D(big case):容易发现,当所有\(x_i+y_i\)的奇偶性一样时,就有解。特别的我们假设\(x_i+y_i\)是奇数(若是偶数,可以先让他们朝一个方向都走1)。然后,我们将机械臂长度定为2的次幂,就可以构造出所有解了。具体的构造方法就是每次把当前的1填到长度为奇数的地方,然后给坐标除以2,不断进行下去。

  • ARC103F:值最大的点一定是叶子,值最小的点一定是重心,我们不妨把最小的点(重心)当作根,去构造有根树。那么显然从根往下满足D值单增。于是我们可以先对所有D排序,就得到了拓扑序,然后从下到上考虑每个点的父亲应该是谁。利用D[u]=D[v]+2*sz[v]-n来对于一个v找其父亲即可。


10.12

  • SPOJ DIVCNTK:直接min25筛。

  • SPOJ APS2:虽然不是积性函数,但比较特殊,也可以套用min25筛的方法做。

  • bzoj 4916:是积性函数,直接min25筛。


10.21

  • CF #517 div 2:4/6

10.25

  • CF edu 53:4/7

10.26

  • CF1073E:直接数位DP

11.1

  • 牛客215F: 用kdtree维护每个点左下方点的个数a,左边点的个数b,右上角点的个数c

11.13

  • CF1076F:\(dp[i][0/1]\)表示做了前i段,最后以0/1结尾的最短长度,然后对于新的一段,贪心去转移

11.30

  • CF1082G:若选择一条边,那么它两个端点都要选取,于是可以将所有的边当作点,于是问题变成了最大权闭合子图问题。

12.2

  • 牛客296B:首先经过简单分析将问题变成了给定一些区间,允许有区间覆盖但不允许区间交,问给定的这些区间是否合法。将所有区间按照左端点升序排序,然后用单调栈维护一个右端点递减的嵌套区间。
posted @ 2018-07-02 13:16  AHU_Amadeus  阅读(635)  评论(0编辑  收藏  举报