退役前的做题记录 Ⅰ
写一下卡特兰数加强数字敏感度:1 2 5 14 42
持续更新到退役(大概
Update: 把日记都删了
P6689 序列
第一步发现对于左括号个数相等的结果序列,它们的出现概率也相等,这个是可以轻松 (n^2) Dp 出来的。
第二步我们需要求一个左括号个数确定的随机序列的最长合法括号子序列期望长度。
掏出我们的重要结论:左括号为 1,右括号为 -1,设前缀最小值是 (Smin),答案就是 (n-S_n+2 imes Smin)。
考虑将相邻的左右括号匹配后消掉会形成这样的:())))((),前缀最小值的绝对值就是这样右括号的个数,玩一下发现是对的。
观察发现 (n-S_n) 是固定的,我们枚举 (Smin) 就可以得到答案了,那么用 (Sminle k) 减去 (Smin <k) 的方案数就可以得到恰好的方案了,算小于的方案就相当于算不得碰到某条直线的方案数,应用折线法即可。
P4769 [NOI2018] 冒泡排序
做到上面那题想到这题了。
首先题意可以转化为计数可以分成两个上升序列的排列个数。
这个东西又可以转化为经典的格子走路问题,我们贪心的这样转化:维护两个上升的序列,选出排列的第一个数开头当第一个序列,另一个序列当成开头为 0,每扫到一个数能放第一个序列就放第一个序列,否则放第二个,不能放就说明不合法。
发现这样一件事:第一个序列相邻两个数 (x,y),那么 ((x,y)) 之间的数在第二个序列是连续且上升的,然后就可以看成格子走路了,从 (0, 0) 开始走路,走到 (n, n),只能向上向右走,每个向右拐点代表着第一个序列填了一个 y 坐标的数,向右平走表示在第二个序列里填了下一个该填的数(这个数是当前最小的未出现过的正整数),一个限制是我们不可以越过 y = x 这条线。
所以这题也不难了,要求字典序要大于 q,我们就枚举一个前缀和 q 相等的部位,强制下一位大于 q 即可。
P6827 「EZEC-4」括号
这题 160 多个 A 的,出题组 A 了 150 多发真是丧心病狂。
暴力 dp 应该都会,以为有什么高妙的少一维状态,没想到是每次多跳一些。
状压预处理,暴力匹配每次跳一步,预处理以后我们可以一次跳多步,就这样卡过去的???
CF755G PolandBall and Many Other Balls
设 (F_n=sum_{}f(n, k)x^k) 其中 (f(n,k)) 表示 n 个球,k 次操作的答案。
我们有简单的 dp。
(f(n,k)=f(n-1,k)+f(n-1,k-1)+f(n-2,k-1))
用生成函数表示就是 (F_n=(1+x)F_{n-1}+xF_{n-2})
这个东西可以矩乘优化,时间复杂度 (Theta(k log k log n))
组合数的办法看起来非常简便,事实上会当 (n ge 998244353) 会因为分母为 0 而出锅。
CF1054H Epic Convolution
(1 le n,m le 10^5,a_i,b_i le 1000,c < 490019)
我们发现 (P) 是比较小的数。
设 (A_k=sum [i ^2equiv k mod P-1]a_i,B_k = sum[j^3 equiv k mod P-1]b_j)
有 (Ans = sum_{i=0}^{P-2}sum_{i=0}^{P-2}A_iB_jc^{ij})
这个东西直接 CTZ 做即可。
[清华集训2016] 你的生命已如风中残烛
这题也超牛逼的!如果会了 Raney 引理那么这道题将秒切。
用卡特兰数来引入一下吧。
相当于一个由 n 个 1 和 n 个 -1 构成的序列,要求前缀和都大于等于 0 的方案数。
Raney 引理其实使用条件限制并不少,这样不平凡的构造也显得非常巧妙。
Raney 是这样一个事实:如果序列的 最大值 为 1,并且序列的和为 1,那么有且仅有一个位置 k 使得 (s_kcdots s_ns_1cdots s_{k-1}) 的前缀和都大于 0。
这个具体数学讲的非常好就不再赘述。
我们给序列里的所有数字标上号,最后在除去,那么序列里有 n 个 1,我们在插入一个标号为 2n + 1 的 1 转化为 Raney 引理的形式。
一共有 ((2n)!) 个 ⚪ 排列,注意到所有的 1 都是等价的,谁他娘的生下来就有两个脑袋,所以我们删去最后一个 1 的概率就是 (frac {1}{n+1}),那么卡特兰数就是 (frac{{2n choose n}}{n + 1}) 了。
回到这题,我们发现最大值没有限制,但最小值有,题目要求前缀和都 (ge 0),我们取反,那么就是前缀和都小于等于 0,但是最大值限制为 1,题目里又保证了和为 0,那么就是所有的后缀和都大于等于 0,所以和上面一样做就行了。
「PA 2019」Podatki drogowe
注意到永远进不了位的,我们可以方便的使用线段树维护 hash 值来比较两个串的大小。
给定一个 k 并不好直接求对应的串,但给定一个串我们可以求出对应的 k,这样我们先二分出一个串,点分治求出对应的 k 即可。
难点大概在于如何求出二分出的这个串,有这样一个性质,你可以从所有串里随机选一个串,因为是随机,期望下的位置大概在中部,所以可以起到类似二分的效果。
我们可以用边分治实现这个过程,大概更好写一些。
HDU6566 【The Hanged Man】
这个男人讲的非常好,建议看这个人的 https://www.cnblogs.com/lhm-/p/13697304.html
CF1270I Xor on Figures
大概是换了一个域的牛牛蹄。
重定义矩阵乘法为 ((a imes b)[x][y]=otimes_iotimes_j a[i][j] imes b[x-i][y-j]) 下标是循环卷积类型的。
那么我们发现单位矩阵就是 (I,I[0][0]=1),我们的操作矩阵是 (F[x_i][y_i]=1),我们现在求一个矩阵 C,使得 (F imes C=A),C 的非零元素个数就是我们需要求得的答案。
如果 C 唯一不就是随便做了?很棒的是:确实。
C 唯一类似于我们要证明 F 有逆元,然后 (C = A imes F^{-1})。
我们探讨这个矩阵乘法的一些性质:
定义加法为对应位异或。可以发现其具有:乘法分配率(对于元素由 0 / 1 组成)。
对于 F 来说,如果存在两个逆元 (FG_1=1,FG_2=1),那么有 (FG_1+FG_2=0),有 (FG=0),其中 (G eq 0),我们有另外一点发现:(F^{2^k}=1),那么 (F^{2^k}G=0) 得出 (G=0) 矛盾。
所以我们暴力对 (A) 乘上 (F^{2^k-1}) 即可。
无题
求解 (frac 1x + frac 1y=frac 1n) 的 x, y 个数,其中 (x,y le 10^{12})
令 (d=(x,y),x=da,y=db),我们有 (da+dbmid d^2ab) 也就是 (a+bmid dab)
可以理解为 a + b 中的质因子来源于 (d,a,b) 三处,不可能来源于 a,b,所以说 (a+b mid d)。
计算式子(来源网络)
[十二省联考2019]字符串问题
码农题,发现原题就是这样一个东西,A 串和 B 串都看成点,A 串向和他有支配关系的 B 串连边,B 串向满足 B 是 A 前缀的 A 串连边,然后跑最长路即可。
问题的难点大概在于连边(其实是写代码),80 分就是先把串翻一翻,然后把后缀自动机建出来,倍增到对应节点利用后缀自动机直接建图即可,100 分就是再后缀自动机上开 vector,然后前缀和建图,听起来是不是非常简单,试看看吧!
[BJWC2018]Border 的四种求法
子串周期查询,给定一个串,每次询问一个子串的最长 border。
这里介绍一种点分治 + 后缀自动机 + 线段树的做法。
字符串就想后缀自动机,对于询问串 (s[l,r]),在后缀自动机上找到 (r) 所在的节点向上跳,我们需要找到满足条件 (p - len[Lca(p,ed[r])] + 1 le l) 和 (p < r) 最大的 (p)。
你可以暴力跳 + 线段树查询,这样复杂度显然是不对的。
考虑树分治,这里我们选择点分治来解决,设分治重心为 (x),因为是有根树,我们分为上半部分和下半部分。
考虑下半部分对整体的贡献,我们可以将下半部分所有的位置 (u) 插入到线段树上,那么 (u) 和另一个点 (v) 的 (LCA) 就是 (v) 和 (x) 的 (LCA) (如果 (u),(v) 在同一子树我们算的贡献不会对答案产生影响,因为错算的 (len[LCA]) 更小),现在我们就是预处理 p,然后枚举 (len[Lca(p,ed[r])]),在线段树上查满足条件最大的 p 即可。
另外一方面,我们需要考虑上半部分对下半部分的贡献,那么插入的时候顺便枚举 (len[Lca(p,ed[r])]),查询的时候直接线段树二分得到最大的 p 即可。
常数略大,但是空间达到了优秀的 (Theta(NSigma))
6300. 「CodePlus 2018 3 月赛」博弈论与概率统计
考虑对于一组询问如何算出答案,容易发现答案的区间是 ([n - m, n])(如果 (n ge m)),我们枚举最终的答案是多少,比如令 (k = n - m),我们转化到网格图上(向上和向右)就发现是不经过 (y = x - 1) 这条线的方案数,在看看 (k = n - m + 1),发现就是经过 (y = x - 1) 而不经过 (y = x - 2) 的方案数,依次类推,我们可以用组合数轻松表示,然后相邻两项发现可以消一下,最后的形式如 (sum_{i=0}^k {n + mchoose k}) 这个东西可以用莫队来求,因为相邻两行可以递推,相邻两列也可以递推!
「BalkanOI 2018 Day1」Election
小清新有趣题,谁能想到竟然是最大子段和呢?
考虑这样一种简单的贪心,我们从前向后扫一遍,如果前缀小于 0 就删掉当前字符,在从后向前扫一遍即可。
直接想不好导出正解,我们需要推式子形式化的说明,先做从前向后的贪心,设原先前缀和和后缀和数组为 (pre_p,suf_p),那么删掉的个数就是 (-min pre_p),考虑现在某个位置的后缀和 $ suf_p'$ 是多少,答案是 (suf_p+(-min pre + min_{q < p} pre_q)),所以我们最终的答案就是 (- min pre - min suf'= -min(suf_p+ min_{q < p} pre_q)=-min(pre_q+suf_p) quad(q < p))
我们再加上总和试试,那么就是求最大子段和了!!然后用数据结构维护即可。