Daimayuan
讲课 2:dp
CF1993G.Xor-Grid Problem
先考虑只有一行的情况,这也是矩阵问题的常见思考方式。那么列替换没有用了,行的话,就是把一个数替换成整个序列所有数的异或和。
然后你多操作几次就会发现,其实操作等价于任意交换了,比如说 \((1,2,3,4)\to (1,1234,3,4)\to(1,1234,3,2)\to(1,4,3,2)\),这里的数字表示哪些位置上的异或和。为什么呢,考虑一次操作时替换的数时能所有数的异或和,第二次替换的数变为了第一次替换的那个位置,(因为其他位置都出现了两次),第三次替换的数又变成了第二次替换的位置,第四次整个序列的异或和变回原样。这样重复操作就能做到任意交换,也即可以做到重排。当然,也有些时候序列中存在所有数的异或和,但只可能有这些数了,所以考虑在序列的末尾加上一个所有数的异或和,那么操作等价于和序列末尾的数交换,所以对于原问题只需删掉一个数然后任意重排即可。
对于矩阵而言也是一样的,补上 \(n+1\) 行和 \(m+1\) 列,其中第 \(n+1\) 行的第 \(i\) 个数是第 \(i\) 列所有数的异或和,\(m+1\) 列同理。特殊地,位置 \((n+1,m+1)\) 应该是原矩阵所有数的异或和,手玩一下就知道了。现在问题转化为,有一个 \((n+1) \times (m+1)\) 的矩阵,你要从中选出 \(n\) 行 \(m\) 列后任意重排,求最小 beauty 值。
根据这个 beauty 的计算方式,可以把它拆成行间的和列间的,这两者互不相关,做完行交换后计算行间贡献,然后无论怎么交换列这个行间贡献也不会改变了。考虑行间的贡献怎么算,枚举删掉了哪一列,然后类似 TSP 做状压,预处理出两行间的贡献减掉删掉一列的贡献即可。注意你不需要枚举删掉哪一行,而只需关注那些状压完后 \(\operatorname{popcount}=n\) 的状态即可。列同理。然后记 \(w_{1,i,j}\) 表示删掉第 \(i\) 行第 \(j\) 列的行间最小贡献,\(w_{2,i,j}\) 表示列间最小贡献,因为独立所以分别计算一遍即可。总复杂度 \(\mathcal{O}(n^32^n)\)。
CF1028G.Guess the number*
考虑询问了之后能得到的是 \(x\) 的上下界,然后你就可以用 \((l,r,i)\) 表示某个询问时的状态。\(i\) 表示进行了 \(i\) 个操作。
然后我们考虑这个每次要怎么分,因为有 \(k\le x\) 的限制,我们一开始其实是不太能问大的的。如果说,我们现在知道 \(l \le x \le r\),也最多只敢问 \(\min(10^4,l)\) 个数,那么考虑 dp。设 \(f_{i,j}\) 表示当前已经知道 \(x \ge j\),询问了 \(i\) 次,最远的能到的 \(r\) 所对应的区间长度是多少,这个地方不存 \(r\) 而存长度是能够方便运算的,同时也能够缩减状态,具体见下文。这个 \(j\) 其实同时决定了初始的位置和询问的数量。先考虑 dp 的部分,划分时需要满足每个子区间都能问出来,同时要走的尽量远。总共能问 \(j\) 次,划分出了 \(j+1\) 个区间,每次都可以确定这个数是大于询问的,等于还是小于,所以考虑执行以下流程:
-
初始时令 \(p=j+f_{i-1,j}-1\),这意味着第一个询问前面得到的那部分区间。
-
每次先执行 \(p+1 \to p\),询问这个 \(p\),然后 \(p+f_{i-1,p+1}\to p\),这是如果 \(x>p\) ,能问出来的长度。总共执行 \(j\) 次。
-
因为最多询问 \(10^4\) 个数,所以 \(l>10^4\) 与 \(l=10^4\) 的能额外确定的区间长度应该是相同的,但是确定的右端点不同,所以前面存长度就可以放在一起算。容易发现在询问的过程中 \(p>10^4\),那么 \(i-1\) 也最多确定长度为 \(f_{i-1,10^4}\) 的区间,这部分直接算即可。同理,对于 \(l<10^4\) 的,当计算过程中 \(p>10^4\) 了也可以直接算。
可以知道 \(f_{5,1}\) 恰好就是给定的 \(M\),那么直接按照这个 dp 的过程交互即可。
具体地说,询问时关心的就是现在的 \(l,r,i\),然后知道 \(l\) 后可以确定要询问 \(\min(l,10^4)\) 个数,然后初始位置也依然是 \(l+f_{i-1,\color{red}\min(l,10^4)}\),前面不用和 \(10^4\) 取 min 是因为我们把 \(\ge 10^4\) 的状态都压到了 \(10^4\) 里,如果出现比 \(10^4\) 大的数直接结束过程了,但是这里还要继续计算而不能像前面一样统一处理,如果 \(p>r\) 就可以跳出循环了。
CF407D.Largest Submatrix 3*
暴力做法是什么?枚举矩形的两边,然后双指针往下扫,更新信息还有 \(\mathcal{O}(m)\) 的复杂度,所以总共是四次方的。考虑优化一部分,肯定要直接确定某条边。每次矩形移动一边的时候,双指针的信息都要重算,但其实移动前已经算了前面的位置了,只需要加上新的一列的影响即可。同时这个过程从整体上来看类似区间 dp,每次考虑增加一个数,所以设 $f_{l,r,i} $ 表示在第 \(i\) 行,左右端点为 \([l,r]\) 的上边界能到哪里。
考虑枚举矩形的左右边界,然后再枚举一个边界,更方便的是枚举下边界,因为这样可以顺序枚举行,要用到的信息都是之前计算过的了。现在我们想知道:对于左边界是 \(l\),右边界是 \(r\),下边界是 \(i\) 的矩阵最大能向上延伸到哪一行。记这个数为 \(f_{l,r,i}\)。
首先,\(f_{l,r,i}=\min(f_{l,r-1,i},f_{l+1,r,i},f_{l,r,i-1})\)。这个原因是比较明显的,当前不能有重复,那比当前小的矩阵里也不能有重复数字。假设这样算出来的值为 \(L\),那么矩阵 \((L,l,i-1,r),(L,l,i,r-1),(L,l+1,i,r)\) 中都没有重复的数字,因而能发生重复的位置只有可能在左右两列。考虑最左边的一列,它只可能与 \((?,r)\) 发生重复,由第一个条件,左右两边的前 \(j\) 个数没有相同的,所以可能重复的地方只有两种:\(a_{i,l}\) 与最右边一列,\(a_{i,r}\) 与最左边一列。考虑维护这个东西,我们关注的是一个数在第 \(j\) 列且不在第 \(i\) 行下的最下面的出现位置,考虑开一个数组维护这个值,空间复杂度 \(n^3\),需要使用 short 才能通过。
注意转移的时候是要由小区间推大区间,因此类似区间 dp,转移的时候要保证小区间都算完了。然后 \(f\) 其实相当于一个行上的前缀 min,所以可以每次另算一个 \(g\) 最后再和 \(f\) 取 max,以及 \(g\) 的初值即长度为 \(1\) 的区间应赋为它这一列上第一个与它相同的数。
NOIP 模拟赛 Day 4
A. 取模
首先一个暴力的 dp 是 \(f_{i}\) 表示 \(i\) 消掉的期望步数,那么 \(f_i=\frac{1}{n}\sum_{j=1}^i f_{i \bmod j}+1\)。
出现了 $\bmod $ 这种东西,考虑使用 \(i \bmod j=i-\lfloor \frac{i}{j}\rfloor\times j\),然后整除分块优化。
现在假设我们要求解 \(f_n\),回顾整除分块的过程,对于 \(i \le \sqrt n\) 的 \(i\),它最多有 \(\sqrt n\) 种,暴力计算。
对于 \(i > \sqrt n\) 的 \(i\),\(\lfloor \frac{n}{i}\rfloor =v<\sqrt n\),对其整段计算,那么就是一个结尾是 \(i-v\),步长为 \(v\) 的等差数列求和,同时这个和一定求到开头,因为右边界是 \(n/(n/i)\),所以直接记 \(g_{i,j}\) 表示以 \(i\) 结尾,步长为 \(j\) 的等差数列 \(f\) 之和即可。那么每次只需要更新 \(i\) 处的位置,\(g_{i,j}=g_{i-j,j}+f_i\)。
B. 线性规划
第一眼差分约束,第二眼不是差分约束,但还是要建图。考虑点 \(i\) 表示变量 \(x_i\),点 \(i+n\) 表示变量 \(-x_{i}\),较小的点向较大的点连边,那么。
- 条件 \(1\) 即 \(x_i>-x_j,-x_i<x_j\),即 \(j+n\to i,i+n \to j\)。
- 条件 \(2\) 即 \(x_i<-x_j,-x_i>x_j\),即 \(i \to j+n,j \to i+n\)。
- 条件 \(3\) 即 \(x_i>x_j,-x_i<-x_j\),即 \(j\to i,i+n \to j+n\)。
- 条件 \(4\) 即 \(x_i<x_j,-x_i>-x_j\),即 \(i \to j,j+n \to i+n\)。
然后这个图显然不能有环,那么它是一个 DAG,假如没有 \(x_{i} =-x_{i+n}\) 这条限制,我们就可以直接按拓扑序从小到大分配权值。
记 \(T\) 为拓扑序数组,类比 2-SAT 的构造过程,若 \(T_x>T_{x+n}\) 则取 \(T_x\),否则取 \(-T_{x+n}\)。考虑这样什么时候会出错:一条链上的 \(x,y\),前面一个点取了正值,后面一个点取了负值。那么 \(T_x>T_{x+n},T_y <T_{y+n}\),因为存在 \(x\to y\) 的路径所以 \(T_x<T_y\),因为这张图对称所以 \(T_{y+n}<T_{x+n}\),推出 \(T_{y+n}<T_y\),矛盾。另一种情况则是前面的负值比后面的负值大,类似分析同样可以导出矛盾,因此这么做就是对的。
C. 子序列
这也太难了。
D. 消消乐
首先你如果不能很好地描述出消除这件事整个题就没法做,当然你可以和 CSP-S2023 T2 一样去拿个栈跑然后分治,但这也太难了。
我们现在的问题是能不能消完,如果能消完肯定有一种方案,比如一个序列 \(\texttt{caabaabbbc}\) 就可以以 \(\texttt{(c(aa)(b(aa)(bb)b)c)}\) 的方式消完,感觉上这就是一个把前一个当成左括号,后一个当成右括号后是一个合法的括号串,那什么叫前一个呢?注意到操作不改变位置的奇偶性,那么不妨假设奇数位为左括号,偶数位为右括号,其实应该再反过来做一遍,但我们没必要真这么做。我们需要的是一种运算,可以随意钦定计算顺序,也就是有结合律,同时不能改变左右位置的顺序,也就是没有结合律,考虑使用矩阵乘法。
给每种字符随机一个矩阵 \(M\),在奇数位放上 \(M\),偶数位放上 \(M^{-1}\),那么一个序列能消空当且仅当这个序列所有的 \(M\) 乘积等于 \(I\),即单位矩阵。如果你不会矩阵求也没关系,可以直接构造对合矩阵 \(M=\begin{bmatrix} a & b \\ \frac{1-a^2}{b} & -a \end{bmatrix}\),同时这样也省略了奇偶讨论。
现在考虑交换两个数后,矩阵形态有何变化,枚举交换的两个位置 \(i,j\),同时记 \(m_i\) 表示第 \(i\) 个位置对应的矩阵。
那么就是由 \(m_1 m_2 \dots m_{i-1}m_im_{i+1}\dots m_{j-1}m_j m_{j+1}\dots m_n\) 变为了 \(m_1 m_2 \dots m_{i-1}m_{j}m_{i+1}\dotsm_{j-1}m_i m_{j+1}\dots m_n\),前后都不变,可以记 \(pre_i\) 表示 \(\prod_{j=1}^i m_j,suf_i\) 表示 \(\prod_{j=i}^n m_j\),注意矩阵乘法没有交换律,\(suf_{i}=m_i \times suf_{i+1}\)。
考虑计算出中间那块,如果这是前缀和,那很好办,就是 \(pre_{j-1}-pre_{i}\) 就好了,但是这是矩阵乘法,但由于我们矩阵是对合的,所以还是可以消一下,记 \(rev_i\) 表示 \(\prod_{j=i}^1 m_j\),那么 \(rev_i \times pre_{j-1}\) 就会是 \(m_im_{i-1}m_{i-2} \dots m_2m_1m_1m_2\dots m_{j-2}m_{j-1}\) 的样子,因为有结合律,所以可以理解为 \(m_im_{i-1}m_{i-2} \dots (m_2(m_1m_1)m_2)\dots m_{j-2}m_{j-1}\) 这样就把前 \(i\) 个都消掉了。
换句话说,交换 \(i\) 和 \(j\) 两个矩阵现在就可以表示为 \(pre_{i-1} \times m_j \times rev_i \times pre_{j-1} \times m_{i} \times suf_{j+1}\),这个式子性质非常好,\(i,j\) 都在一起(因为 \(m_i,m_j\) 可以枚举颜色后直接处理),枚举颜色 \(x,y\),且 \(i\) 的颜色为 \(x\),\(j\) 的颜色为 \(y\),那么现在这坨东西的乘积 \(=I\),所以 \((pre_{i-1}\times m_y \times rev_i)^{-1}=pre_{j-1} \times m_i \times suf_{j+1}\)。前面那个东西求逆还是要倒过来,也就是 \((m_1m_2 \dots m_{i-1}m_y m_i m_{i-1}\dots m_1)^{-1}=m_1m_2\dots m_{i-1}m_im_ym_{i-1} \dots m_2m_1=pre_{i} \times m_y \times rev_{i-1}\)。
那么钦定 \(i<j\),枚举颜色用 map 记录即可,要重载小于号。
讲课 4:数据结构
CF193D.Two Segments
肯定不能枚举原序列的位置区间,因为那样有四个变量还要去重,那么考虑枚举值域区间。记 \(f_{l,r}\) 表示值域在 \([l,r]\) 中的数在原序列中划分成的连续段数量。那么答案是 \(\sum_{1 \le l<r \le n}[f_{l,r}\le 2]\),是两个非空区间交起来因此 \(l \neq r\)。
扫描线 \(r\),动态维护 \(f_l\) 表示 \(f_{l,r}\),因为 \(f_{l,r}\ge 1\),因此 \(\le 2\) 只可是最小值,次小值,统计这两个数的出现次数即可。好像有说法是次小值是最小值 \(+1\) 然后直接做,但不得保证有次小值吗,不懂。其实你查询应该是 \(r-1\),但那样顺序就比较麻烦啊,考虑直接算最后减掉 \(n\) 即可。
现在考虑加一个数 \(r\) 对 \(f\) 的影响。我们先把整个 \(f_{l,r}\) 的转移写出来:
- 首先假设 \(r\) 没有相邻的数,\(\forall f_{l,r}\leftarrow f_{l,r}+1\)。
- 若 \(r\) 的位置左边的数已经加入过了,也就是 \(pos>1\) 且 \(a_{pos-1}<r\),那么可以向左合并,\(f_{l,r}\leftarrow f_{l,r}-1(l \le a_{pos-1})\),因为要包含 \(a_{pos-1}\) 这个数。
- 若 \(r\) 的位置右边的数已经加入过了,也就是 \(pos<n\) 且 \(a_{pos+1}<r\),那么可以向左合并,\(f_{l,r}\leftarrow f_{l,r}-1(l \le a_{pos+1})\),因为要包含 \(a_{pos+1}\) 这个数。
线段树维护区间加法即可。
CF997E.Good Subsegments
现在你已经会了数一个序列值域连续段的数量,现在让我们来考虑子区间询问。
类比全局做法,我们还是想要枚举右端点,那么可以先把询问离线下来,那么询问的时候不再询问 \([1,r]\) 的最小值而询问 \([l,r]\) 就能得到左端点在 \([l,r]\) ,右端点在 \(r\) 的答案。但这还不够,我们还想得到所有 \(r' \in [l,r]\) 的答案,考虑在线段树上额外维护历史和。具体地说,你要对每一个线段树上的节点 \(p\),记录 \(cnt_p\) 表示 \(p\) 所代表的区间中最小值被计算了几次,同时维护答案。对于一个点 \(p\),如果要对它 pushdown 的话,左右儿子不一定都有贡献,需要满足左儿子的最小值与当前点的最小值相等,左边才会有最小值做出贡献,左儿子的答案就要加上左儿子中最小值的数量与贡献次数之积,右边也是同理。那么为了正确算出左右儿子的最小值,要先下放区间加标记,在下放贡献标记。
考虑修改的时候,如果一个点的最小值改变了,那么它一定在修改时被递归过了,那么我们也肯定对它做了 pushdown,重新计算了最小值和最小值的出现次数,同时如果一个点最小值没变,那么最小值出现次数也没变,不需要动这个点,用到的时候再算 \(tag\) 就好了,所以这个做法就是对的。
每次做完 \([1,r]\) 这个前缀后,就给根节点打上 tag,表示这一部分的答案又贡献了一次,这样为什么不会算上右边的位置呢?因为左边的最小值一定是 \(r\),而右边没动过也是 \(r+1\),因此最小值一定在左边。然后查询的时候也是查 \([l,r]\),就恰好问到了所有合法的区间右端点的贡献之和,因为 \(r'<l\) 的肯定不会贡献到 \([l,r]\) 中,否则一定贡献到了。
CF765F.Souvenirs
有厉害的压位 trie/链表 + 回滚莫队做法和分块做法,但我太菜了/kk。
还是考虑离线然后固定右端点,维护数组 \(f_l\) 实时表示 \([l,r]\) 这个区间的答案,那么询问就是扫到 \(r\) 的时候 $[l,r] $ 的后缀和。然后钦定 \(a_l\ge a_r\),因为你可以 \(-a_i \to a_i\) 后再做一遍。
现在我们要做的就是找到 \(r\) 前面第一个 \(\ge a_r\) 的数,然后重复这个过程,如果序列递减就是 \(n^2\log\) 的,很好地劣化了复杂度。
考虑只保留有用点对,首先找到前面第一个 \(\ge a_r\) 的位置记为 \(j\),下一个位置 \(a_k \ge a_r,k<j<r\),那么 \((k,r)\) 能取到的点 \((k,j),(j,r)\) 也一定能取到,不妨要求 \((k,r)\) 必须是最好的那个,因为这里带不带等号显然不影响答案。那么 \(a_j-a_r >a_k-a_r\),可以得知 \(a_k<a_j\),因此 \(a_j-a_k>a_k-a_r\),即 \(a_k<\frac{a_j+a_r}{2}\),因为是小于号,所以若 \((a_j+a_r) \equiv 0(\bmod 2)\) 还要额外减 \(1\)。我们还要求了 \(a_k \ge a_r\),那么 \(a_k\) 能用需要满足 \(\frac{a_j}{2}>\frac{a_r}{2}\),但是 \(a_k\) 每跳一次 \(a_j\) 的值又相当于变成了原来的一半,所以跳的次数总共是 \(n \log V\) 的。
实现的时候不需要主席树,使用权值线段树找在合法的值域区间中最靠右的点即可,如果没有就返回 \(0\),这么做是对的的原因是如果这个值域区间在当前这个位置的右边还有合法的数的话显然是比这个位置的数要小的,那么选它严格比选当前这个位置好,那我们肯定就选了。再跳的时候你需要允许左右端点相等的情况出现,但这样可能会进入死循环 \((1,1)\),因此在 \(l+r\) 为偶数的时候额外减去 \(1\) 是必须的。有一组 Hack 是:
5
8 9 6 7 8
1
1 5
CF702F.T-Shirts
势能分析。
首先如果对于一个人去考虑,那么这个过程好像是不太能优化。
那么对物品考虑,按照题目描述给物品排序,记 \(c\) 为当前物品的价格,每次给余钱 \(\ge c\) 的人余钱减去 \(c\) 答案加 \(1\),好像用平衡树就行了,但是这东西还是不能直接做,因为 \(\ge c\) 的减去 \(c\) 后可能比 \(c\) 小,但是 fhq 的合并需要值域不交。
好像可以的解决办法就是把 \(\ge c\) 的数做完减法后暴力插入,但这样显然复杂度会是错的。仔细分析,可能发生值域交叉的位置只有可能在 \([c,2c)\) 间,因为 \([2c,+\infty)\) 的数减去 \(c\) 后还是大于 \(c\),而 \([0,c)\) 中的数则不用管。
那么把 \([c,2c)\) 中的数拿出来,暴力修改后暴力插入,这样复杂度是对的,因为对于 \([c,2c)\) 来说,减去 \(c\) 相当于这个数的大小至少缩小了一半。所以一个数至多被暴力修改 $\log $ 次。对于 \([2c,+\infty)\) 的数直接打 \(tag\),最后 dfs 一遍统计答案,总复杂度 \(\mathcal{O}(n \log n \log V)\)。
关于一些实现,后续插入的时候需要保有一个点的答案,权值,编号,最好的方式是直接插入一个平衡树上的节点,那么插入时要把儿子清空防止死掉。但是编号可能不需要记,因为插入时的顺序就是回答的顺序,但是没有实现过,不太确定。
CF1677E.Tokitsukaze and Beautiful Subsegments
考虑最大值,那么常见做法是单调栈维护左右两端点,记为 \(L_i\) 和 \(R_i\)。
然后枚举 \(i\),基于启发式分裂,我们可以选一边枚举,假设枚举的是 $i \le j< R_i $,由于对于一个右端点确定的区间,区间长度越长越容易合法且合法后一直合法,那么我们可以算出对于每个 \(j\),左端点最右到哪里能合法。
假设算出来了,记为 \(l,r\),那么我们枚举 \(j\) 做扫描线,每次就将在右端点的区间 \([l,r]\) 的贡献 \(+1\),查询就询问 \([l,j]\) 的和即可。
现在我们的问题就是求出这个取值范围,记左端点最大能取到 \(r\),首先为了使最大值是 \(a_i\),所以 \(r\le i\),然后先考虑两个数都在 \(i\) 和 \(i\) 的左边,那么枚举 \(a_i\) 的因数对 \((x,y)\),那么需要满足 \(L_i < pos_x,pos_y\le i\),那么这样右端点只要有这一组就行了,就饿可以用 \(\min(pos_x,pos_y)\) 更新 \(r\)。
然后扫右端点,每次只更新右端点的贡献,如果 \(a_i \bmod a_j=0\),那么考虑 \(a_i/a_j\) 的位置 \(p\),要求 \(p<j\) 且 \(p>L_i\),那么就能用 \(p\) 更新 \(r\)。如果 \(L_i+1 \le r\) 就把这个区间 \([l,r]\) 挂在 \(j\) 这个右端点上。
注意细节,题目要求选取的两个数不能相同,因此若 \(a_i/a_j\) 的位置就是 \(a_j\) 的位置,那么它不能用于更新,一开始更新的时候也是如此。
时间复杂度 \(\mathcal{O}(n \sqrt n+n \log ^2n)\),可以优化至 \(n \log ^2n\)。
NOIP 模拟赛 Day 5
A.数位背包/Homework
神秘问题。
首先你看这个题的数据范围,dp 放什么都会爆,也不能直接贪心,考虑二分答案,check 就是看背包体积 \(\le mid\) 的最大价值能不能 \(\ge k\)。同时把体积为 \(2^{x}\) 的物品塞到编号为 \(x\) 的 vector 里。
如果 \(mid\) 是奇数,就意味着我不管前面怎么选,最后总可以多选一个 \(0\) vector 中的数吗,这个数肯定选最大的最好。然后转化成偶数。偶数的做法就是最有方案肯定是 \(0\) vector 中两个两个选,那么可以直接将两个数合并移动到 \(1\) vector 中。
从低位到高位处理,每次都进行这个过程,即可得到答案。
如果提前将 vector 中的数排序后归并,复杂度是 \(\mathcal{O}(n \log n+n \log V)\),暴力是 \(\mathcal{O}(n+n \log ^2V)\)。
讲课 6:计数
CF1944F.Counting Is Fun
重温条件,从左往右做操作,考虑如果想消第 \(i\) 个数,只可以用前 \(i-2\) 个数,注意这里 \(i\) 是被加一的位置。假设前面的已经合法,那么前 \(i-2\) 个数消成 \(0\) 的余量就是 \(\sum_{j=1}^{i-2} b_{j}=a_{i-2}\)。人话:\(a_{i-2}+a_i-a_{i-1} \ge 0\),为啥只要 \(\ge 0\),因为我这里是做加一,这里太大了不是我需要考虑的,而是由后面考虑,但是像 \(n\) 后面就考虑不到了。所以我们要求 \(a_{n+1}=0\),其实也是为了满足 \(n\) 上的限制:原来 \(n\) 是序列的末尾,因此只有左边的数可以贡献,加上 \(n+1\) 可以确保前面的都被消成 \(0\)。然后记两个数就能通过 1。
考虑对状态做点手脚,假设 \(i\) 不合法,\(i-1\) 不合法,那么 \(a_{i-3}+a_{i-1}-a_{i-2}<0,a_{i-2}+a_i-a_{i-1}<0 \rightarrow a_{i-3}+a_i<0\),这是不可能的。
那么可以用一点容斥,设 \(f_{i,j}\) 表示前 \(i\) 个位置,第 \(i\) 个位置为 \(j\) 的答案,转移是对前一位所有的方案数求和再减去产生了不合法的方案数(这个不合法应该在 \(i-1\) 处产生)。
\(f_{i,j}=\sum_{v}f_{i-1,v}-\sum f_{i-2,k}\times w\),\(w\) 是神秘系数。因为 \(i-1\) 不合法时 \(i-2\) 一定合法,容易得到不和法的条件是 \(k+j-v<0\),也就是 \(k+j<v\),所以 \(v\in(k+j,m]\),所以 \(w=\max(0,m-k-j)\)。
现在只需要求 \(\sum f_{i-2,k}\max(m-j-k,0)\) 这个咋求呢。\(m-j-k\ge 0\) 则 \(k \le m-j\),所以只算这部分就行了,剩下的是 \(\sum_{k} (m-j-k)f_{i-2,k}\),拆成两个前缀和就行了。
CF1842H.Tenzing and Random Real Numbers
拜谢 WA90。
首先给所有 \(x_i\) 减去 \(0.5\) 使得右边的限制为 \(0\),这样就好做得多。
然后限制就是 \(x_i+x_j \ge 0\) 或 \(x_i+x_j \le 0\),\(x_i+x_j\) 的正负应由绝对值较大的一方决定,假设 \(|x_i|\le |x_j|\),那么限制 \(1\) 就是 \(x_j \ge 0\),限制 \(2\) 就是 \(x_j \le 0\)。
因此,我们可以按照 \(|x_i|\) 从小到大的顺序进行状压 dp,每次考虑新插入一个数,如果这个数可以为负就贡献一次,可以为正就再贡献一次,就这样简单更新即可。
注意有自己和自己的转移的限制啊,转移时要注意一下。
至于这里为什么是 \(2^n\) 以及这个“从小到大”是怎么说的,其实都是实数随机到任何一个数的概率都是 \(0\)。
CF1792F1.Graph Coloring(easy version)
首先对题目中的限制做一些描述,前两条没有用,我们就随便数,最后减去 \(2\) 就行。第三条是说,对于任意一个点集 \(S\),只保留 \(S\) 中的点和红色或蓝色的边后这 \(S\) 个点联通。也就是 \(S\) 的红色导出子图和蓝色导出子图正好有一个联通。
考虑一个结论:一个图和它的补图至少有一个联通。假设当前图 \(u,v\) 在一个联通快里,\(w\) 在另一个连通块里,那么补图中肯定存在边 \((u,w),(v,w)\),因此,\(u,v\) 仍然联通,而且 \(w\) 也与它们联通。那么一张完全图,每条边不是红的就是蓝的,也可以理解为蓝色图为红色图的补图,因此这两者有一个联通,那么它那一部分的条件就直接满足了;再考虑 \(S=V\),那么蓝色,红色不能同时联通,因此需要有一种颜色恰好不连通,两种颜色情况对称,假设它是蓝色。
设 \(f_n\) 表示 \(n\) 个点的蓝色不连通图个数,那么这个图考虑蓝边必然是有好几个连通块,考虑枚举其中 \(1\) 号点所在的连通块大小,这也是老套路了,不然会算重。假设是 \(j\),那么我们要关心这 \(j\) 个点的蓝色连通图的数量,这与我们的定义不符。但是红色与蓝色对称,红色不连通也可以看做蓝色联通,因此 \(f_j\) 就是 \(j\) 个点的蓝色连通图数量。对于另外一部分,即剩下的 \(n-j\) 个点,它们是红色联通还是蓝色联通并不重要,所以方案数是 \(2f_{n-j}\),然后这两个点集之间的连边必须是红色,否则这两部分就连接起来了。但是如果 \(n-j=1\),也就是只有一个点了,那么它内部没有边也就没有联通这一说了,因此若 \(j=n-1\) 则没有乘 \(2\) 的系数。因此转移方程是 \(f_i=\sum_{j=1}^{i-1} \binom{i-1}{j-1}f_jf_{i-j}(2-[j+1=i])\)。
说不定卡卡常能过 F2 呢?

浙公网安备 33010602011771号