近期总结11.14
看lby博客
CF623E Transforming Sequence
题意:求有多少个序列 \(a_{1...n}\),\(0\le a_i<2^k\),且令 \(b_i=a_1|a_2|...|a_i\),满足 \(\forall i,\space b_i>b_{i-1}\),答案模 \(10^9+7\)。
\(1\le k\le 3\times 10^4,\space 1\le n\le 10^{18}\)
首先 \(n>k\) 答案为 \(0\)。
每一位都一样,每个 \(a_i\) 至少有一位之前没有出现的 \(1\) 位。
设 \(f[i,j]\) 表示前 \(i\) 个数,\(b_i\) 有 \(j\) 个 \(1\) 的方案数。
后面是卷积的形式,但有个 \(j!\) 不好直接多项式快速幂。
考虑倍增,当 \(n\) 为偶数时递归处理 \(f[\frac i2 ,]\) 的值,然后就能直接做了。
需要写个 \(\text{MTT}\),比较麻烦。
CF710F String Set Queries
题意:一个字符串集合,每次操作有 \(3\) 种:
-
插入一个字符串
-
删除一个字符串
-
给出一个文本串,求集合内字符串在文本串的出现次数之和。
强制在线。
一种新的数据结构——二进制分组
首先,有两种暴力思想:
-
扫一遍集合内所有的字符串,计算答案。
-
动态维护集合内字符串的 AC 自动机,让文本串在上面匹配,但每次修改需要重新建 AC 自动机。
前者修改快,后者查询快,考虑把两者结合起来。
先不考虑删除。
每次插入一个字符串,我们可以先给这个字符串单独建立一个 AC 自动机,称这个字符串处于单独的一组。
当我们发现最靠后的两个组大小相同时,我们暴力合并两个组的 AC 自动机,这就很像 2048 消除。
时间复杂度证明考虑线段树。
然后删除操作开另一个二进制分组,插入和删除相减就是答案。
AGC035D Add and Remove
题意:给出 \(n,a_{1...n}\),这 \(n\) 个数排成一列。你每次删除其中一个下标 \(\in [2,n-1]\) 的数,然后他两边的数加上他原来的值。求最终 \(a_1+a_n\) 的最小值。
\(1\le n\le 18\)
不能状压啊
考虑区间 DP。
发现每次删一个数,会把他的贡献寄托给相邻两个数。
设 \(c(i)\) 表示 \(a_i\) 的贡献系数。
钦定删除 \(a_i\) 时其左边的数为 \(a_x\),右边的数为 \(a_y\),那么他的贡献系数为 \(c(i)=c(x)+c(y)\)。
设 \(f[i,j,c_1,c_2]\) 表示消除 \(i+1...j-1\) 这一段,\(c(i)=c_1,c(j)=c_2\),最小的贡献和。
听说不用记忆化也能过,能证明出时间复杂度为 \(O(2^nn)\)。
CF1887D Split
题意:一个排列 \(a_{1...n}\),每次询问 \([l,r](l<r)\),是否存在一个 \(p(l\le p<r)\),满足 \(\max_{l\le i\le p}\{a_i\}<\min_{p<i\le r}\{a_i\}\)。
\(1\le n,q\le 3\times 10^5\)
这题的套路与之前一题一模一样。
以前我们都是枚举限制,然后维护条件。
这里我们枚举条件,然后贡献限制。
一个询问 \([l,r]\),可以考虑枚举 \(i(l\le i\le p)\),表示 \([l,p]\) 中最大值的位置。
那么 \([l,p]\) 中每个数都 \(\le a_i\),\([p+1,r]\) 中每个数都 \(>a_i\)。
我们先不管所有询问,枚举这样的 \(i\),考虑他会对哪些询问区间做贡献。
设 \(L_i,R_i\) 表示左/右边第一个大于 \(a_i\) 的数的位置,可以发现,可以贡献的询问区间为:
-
\(l\in [L_i+1,i]\)。
-
令 \(P_i\) 为 \(R_i\) 右边第一个小于 \(a_i\) 的数的位置,\(r\in [R_i,P_i]\)。
我们分别求出这些位置。
放到二维平面上,我们把每一个位置的贡献看做一个 \(x\in[L_i+1...i],y\in[R_i...P_i]\) 的矩阵,每次查询相当于查询 \((l,r)\) 这个点是否被至少一个矩阵覆盖。
扫描线即可,时间复杂度 \(O((n+q)\log n)\)。