杂题
6.1 T2 新居规划
为什么这个题没做出来(流泪)
考虑首先一个物品的贡献有三种:\(a_i/a_i+b_i/a_i+2b_i\)。我们特判 \(m\) 个位置全被塞满的特殊情况,然后可以把环视作一条链,链的最后一个位置必须为空。
不难看出如果有多个 \(\gt 2\) 的连续段我们可以选择一个连续段,然后把其余 \(\gt 2\) 的连续段的中间部分塞进去。这样就只剩下:若干孤立点,若干长度 \(=2\) 的段,和至多一个长度 \(\gt 2\) 的段。
然后说,我们可以把一个长度 \(=2\) 的段,\(b_i\) 较大的那个塞进另一个段的中间,这样答案一定不会变小。所以可以更进一步简化为若干孤立点,和至多一个长度 \(\ge 2\) 的段,这一步转化非常重要。
全为孤立点的情况也是容易的,特判之。一般情况下,我们会选出:\(p\) 个孤立点,\(2\) 个 \(a_i+b_i\) 的,以及 \(q\) 个内部点(\(a_i+2b_i\)),需要满足 \(2p+3+q<=m\)。
如果 \(p,q\) 固定,可以用模拟费用流来解决。固定 \(q\) 容易证明答案关于 \(p\) 上凸,二分之有一个简单的 \(O(n\log^2 n)\) 做法,但鉴于模拟费用流需要维护的堆很多,所以这个做法的常数特别大,应该是无法通过的。
这种二元形如 \(Ax_1+x_2\le m\) 的流量限制有一个通解:我们从小至大增量枚举 \(x_2\)(其实枚举 \(x_1\) 也可以),就相当于是每次都往 \(x_2\) 这边增添一条流量,\(x_2\) 增大的时候 \(x_1\) 肯定只会减小,所以我们找一条权值最小的 \(x_1\) 引出的增广路,看去掉以后答案会不会更优即可。然后就算去掉以后答案不会更优但是 \(2p+3+q\gt m\) 了我们依旧需要强制退掉这条流量。这样就在 \(O(n\log n)\) 的时间内解决了本题。
6.1 T3 小班课
这个题倒是比较有思路,但是采用的手动构造出现了一点问题修不出来,没有意识到存在一种更优美的方式避免手动构造。
首先一组学生能上到课的必要条件是学生能和课程之间构成一组完美匹配。直接猜测这个也是充分条件。
怎么构造?我们需要满足两个条件:
-
可能会出现一个哥们明明能选前面的课,但是和后面的课匹配上的情况。
-
对于给定的匹配我们来构造一个顺序:那么对于一个人 \(A\) 而言,如果有一个人 \(B\) 选了对 \(A\) 而言比他优先级更高的课,那么 \(B\) 就得在 \(A\) 前面。而这样的拓扑结构不能出现环。
先解决第二个问题:我们会发现沿着环的方向把环上所有人的选课移动一位,每个人还是能选到想选的课,而且优先级会更高。
在解决第一个问题:我们直接暴力检查每个人是否匹配还能往前移动即可。
这样暴力检查构造有点繁琐,其实有个很牛的方法:把最大匹配变成带权的,对于一个人,优先级越高的课程费用越低,这样就容易证明不会出现上述的两种情况,第一种情况直接费用就变小了,第二种情况你把环上的 shift 一下后肯定每个人的费用还是变少了。然后就很优美的拿下了。
ABC356G FreeStyle
如果只有两种方案,我们可以把两种方案组合成一个新的方案,然后只使用这个方案,具体的,设原本的方案为向量 \(a,b\)(横坐标是距离纵坐标是代价),显然新的方案是 \(\mu a+(1-\mu)b\),那么也就是 \(a,b\) 对应的点的连线上的每个点代表的方案都能取到。
进一步地,如果三个点呢?从一条直线变成了一个三角形。很容易看出规律:这 \(n\) 个点构成的凸包就是可取方案构成的点集的全体。
设 \(k=\frac{c}{d}\),我们实质上需要的方案应该是满足:\(\frac{a}{b}\le k\) 且 \(b\) 最大的方案。
因此容易看出,只有凸包下凸壳上的点可能有用。这是所有直线 \(b=v\) 和凸包交点最小值构成的全体。所以我们建出下凸壳就好了。更进一步的其实应该是从 \(c\) 最小的那个点开始的下凸壳。
然后从右向左考虑下凸壳上的每条线段:可以看出这条线段的点的 \(\frac{b}{a}\) 构成一个区间,把所有 \(k\) 在这个区间(\(k\) 可以大过上界但不能小于下界)的询问拉出来在这条线段上找到最优秀的点即可。
时间复杂度 O((n+q)\log)$,瓶颈在于排序。
ABC347G Grid Coloring 2
当 \(k=2\) 的时候除了最小割没有什么很好的解决办法,于是考虑 \(k=5\) 同样使用最小割。
从 Flamire 大神那里学到一个很好用的形式化描述最小割的方法就是相当于有若干个变量 \(x_1\sim x_n\) 然后你要最小化 \(\sum_{u,v}x_u(1-x_v)\),并且钦定 \(x_s=1,x_t=0\)。
本题同样使用这个方法来描述建图:首先创建 $6& 个变量 \(x_{i,j,v\in 1\sim 6}\) 分别表示 \((i,j)\) 是否大于等于 \(v\)。然后 \(x_{i,j,6}\) 实际上就是 \(t\),\(x_{i,j,1}\) 实际上就是 \(s\)。然后 \(x_{i,j,v+1}\) 向 \(x_{i,j,v}\) 连 \(\infty\) 的边,表示不能出现前者为 \(1\) 后者为 \(0\) 的情况。
然后那些已经确定的格子对周围的贡献也很好确定,直接放在 \(x_{i,j,v}\rightarrow x_{i,j,v+1}\) 的边权上即可。关键是两个未确定格子的值的差的平方这个东西怎么转?考虑这样拆:对于两个相邻格子 \(A,B\),若 \(x_{A,i}=1\) 且 \(x_{B,j}=0\)(\(i\ge j\))则产生 \(1+[i\neq j]\) 的贡献,发现这个就把平方化掉了,有点组合意义的那种感觉啊。
然后做完了。。
6.3 T1 B
为啥第一题的名字叫 B?
不妨就认为从 \(L_1\) 出发 \(R_1\) 结束。然后说考虑这个过程就是你第一步向右边有若干个点能一步走到,这些点在第二步又同时向左部点拓展。。。所以整个过程可以用 \(f(x,y,z,0/1)\) 表示。其中 \(0/1\) 是位于哪一侧,\(x\) 是当前侧已经被拓展过的总点数,\(y\) 是当前侧有几个点是刚刚拓展过的,\(z\) 是对面侧有几个点被拓展过。转移就枚举拓展到对面侧的点 \(t\) 然后转移到 \(f(z+t,t,x,1/0)\) 即可。
然后光记录概率肯定不够,然后你 dp 状态里又不记录长度,所以要额外记录一个期望的数组。这个就是大体细节然后完善下就 ok 了。
qoj Binary Substrings
不是,这个我哪会啊??
一个很牛的上界肯定是每个子串都互不相同。那肯定做不到啊?长度为 \(1\) 的就做不到。
事实上若 \(2^k+k-1\lt n\) 那你一定做不到长度 \(=k\) 的子串互不相同。找到最大的这样的 \(k\),然后我们断言答案就是:说所有长度 \(\le k\) 的串都出现,然后长度 \(\gt k\) 的串都互不相同,这肯定是上界,然后构造一个方案使得其一定能取到。
那就只用关注 \(k\) 和 \(k+1\) 两个长度就好了。
然后回忆起一个做了一万遍的东西:构造一个长度为 \(2^k+k-1\) 的序列使得每个长度为 \(k\) 的串都出现过一次。就是你直接把长度为 \(k-1\) 的串当点,然后 \(0/1\) 的拓展方式作为边连,这个图一定有欧拉回路,跑一下就行了。这个我还是很会的!
然后我就不太会了:你考虑现在其实是 \(n\gt 2^k+k-1\)。首先把刚才的 \(\pmod{2^{k-1}}\) 下的欧拉回路变成 \(\pmod{2^k}\) 意义下的哈密顿路,这个我就想不到。。然后再从 \(\pmod{2^{k+1}}\) 的角度下看,相当于要找一条点不重复的路径,且满足每个 \(x\) 而言:\(x\) 和 \(x+2^k\) 至少有一个哥们出现在了路径里。
我们已经在 \(\bmod 2^k\) 意义下构造出了一个哈密顿路,把点转回 \(\bmod 2^{k+1}\) 意义下,然后可以得到一个长度为 \(2^k\) 的简单环,满足条件二。但是我们需要的路径长度是 \(n-k\) 而非 \(2^k\)。
首先:对于每个 \(x\) 和 \(x+2^k\),它们能走到相同的两个点。如果我们为 \(x\) 钦定一个后继,那 \(x+2^k\) 就选择另一个当后继,然后整个图会变成若干个简单环。
现在就是我们已经有一个 \(2^k\) 的大环了,还有若干个小环。一定存在一个 \(x\) 使得 \(x\) 在大环上而 \(x+2^k\) 不在(都是在模意义下的语境),交换两个人的出边,则就把大环拼接到了小环上。
显然每一次新的环都一定满足条件二。但是最后可能得到一个长度 \(\gt n-k\) 的环,在这个环上选择一段长度为 \(n-k\) 的路径不一定满足条件二。考虑第一次让环长 \(\ge n-k\) 的时候从原来的大环的断点开始,作为起点。那么这条长度为 \(n-k\) 的路径就一定是先经过完整个大环再走一部分小环,而大环是满足条件二的所以现在的路径就依然满足条件二。
6.5 T2 eternal
看到这个循环串的形式联想到优秀的拆分,所以枚举循环节长度 \(d\) 然后按 \(d\) 分块。方便起见我们让 \(n\) 统一为 \(d\) 的倍数然后只需要注意一下最后有些串不能取(即使可能满足至多改动一个字符就能相同),这是一点细节。
不妨先考虑约束是完全相同的情况:考虑我们对于起始下标模 \(d\) 的值 \(x\) 分开来讨论,对于两个相邻的块,当 \(x\) 为多少的时候,我们的串不能跨过这个块?显然我们对每个块处理出第一个位置 \(p\) 使得 \(s_p\neq s_{p+d}\),同理处理出最后一个。然后不合法的 \(x\) 就能表示成 \(O(1)\) 个区间的形式。
此时考虑扫描线:从前往后枚举每个块然后维护一个 \([0,d)\) 的数组,分别表示每个 \(x\) 而言,如果串的结尾是当前所在块,那么串的开头最长能延伸到哪里。显然每一轮对数组求和就是答案。
然后我们的操作就是区间清零和全局 \(+1\),求全局和。容易用线段树维护。
现在再考虑允许一个位置不同的情况,只需要类似地处理出每个块的前两个和后两个不同的位置,然后一样能拆出 \(O(1)\) 个不合法区间,就拿下了。
时间复杂度 \(O(n\log^2 n)\),常数较大。
qoj5830 树
这道题是一道非常有新意的题,可以说为解决比较经典的一类问题引入了一个新的方法。
先考虑传统做法:上倍增,维护 \(f(u,i)\) 表示 \(u\) 子树内当 \(k=2^{i}-1\) 时的答案。(这样会比 \(k=2^i\) 好做很多)。\(f(u,i)\) 依赖 f(u,i-1)$,且依赖子树内所有距离为 \(2^{i-1}\) 的点 \(v\) 的 \(f(v,i-1)\),还依赖距离在 \([2_^{i-1},2^i)\) 的点里有多少个数满足二进制位的第 \(i-1\) 位是 \(1\)。
后两者可以从枚举 \(u\) 转而枚举 \(v\) 然后去做树上差分。然后我们再来考虑询问。
询问就比较麻烦,因为你 \(v\) 向上做贡献的距离不一定是形如 \(2^i\) 的,它可以是任意一个数。
我们要做的是实际上是这样一个问题:多次询问某个点子树内距离 \(=k\) 的点的所有信息(\(\lt k\) 的信息可以由整个子树减去 \(=k\) 的所有点的子树信息来得到),那么考虑直接 dfs。在 dfs 的过程中对每个深度都维护对应的信息和。然后用 dfs 后减去 dfs 前来得到子树内该深度的信息。这样可以在 \(O((n+q)\log n)\) 的时间内解决本题,但劣势非常明显:代码难度大,常数不小,并且必须离线。
而本题存在这样一个代码难度小且支持强制在线询问的做法,这个思想也适用于解决一系列的子树问题,只要信息有可减性:
先解决我们后面要做的那个“实际性问题”:我们直接维护 \(f(u)\),传统的方法里 \(f(u)\) 就是 \(u\) 子树内的信息,而此时的 \(f(u)\) 定义为:所有和 \(u\) 同深度且 dfs 序先于 \(u\) 的点(包含 \(u\)),它们子树的信息并,容易看出不同的子树是不交的。所有可以理解为我们按照 bfs 序给所有节点重新编号,就是把树展成平面图然后从上往下从左往右编号那种形式。
现在维护的是从第 \(dep_u\) 层一直到底的信息,考虑维护第 \([dep_u,dep_u+k)\) 层的信息:只需要找到这样一个点 \(v\),使得 \(dep_v=dep_u+k\) 且 \(v\) 的 \(k\) 级祖先的编号小于等于 \(u\) 的,且 \(v\) 自身的编号尽可能大。那很显然 \(f(u)-f(v)\) 就是第 \([dep_u,dep_u+k)\) 层的信息。再考虑寻找这个 \(v\):同样使用倍增,设 \(to(u,i)\) 是 \(k=2^i\) 时去向的点则容易从 \(to(u,i)\) 递推到 \(to(u,i+1)\)。而 \(to(u,0)\) 就是 \(u\) 的最后一个儿子(如果没有儿子,那么就继承同深度上一个点的 \(to\),把这个“上一个点”记作 \(pre_u\))。
然后上面我们就求出了一个 \(G(u,k)\),再减一下 \(G(pre_u,k)\) 就是我们想求的了呀,啊???
再回顾一下原问题怎么做,首先是 \(f\) 的预处理,不再需要那么麻烦了:我们维护一下 \(cnt(u,0/1)\) 表示 \(u\) 子树内距离 \(\lt 2^i\) 的点里第 \(i\) 位是 \(0/1\) 的点数。然后你就可以 \(O(1)\) 算出点 \(u\) 子树内距离在 \([2^k,2^{k+1})\) 的点内第 \(i\) 位是 \(0/1\) 的点数。
然后是询问:这次是我们有 \(O(\log n)\) 次询问,每次问的是一个点内距离 \([2^t,k)\) 内的信息,其中 \(k\) 是定值。那花费 \(O(\log n)\) 的代价找到第 \(k\) 层的那个 \(to\),然后每个 \(2^t\) 层的 \(to\) 都是可以 \(O(1)\) 求出的。所以就在 \(O(\log n)\) 的时间内同时回答了这 \(\log n\) 个询问。
时间复杂度 \(O((n+q)\log n)\)。以后碰到有可减性的和深度有关的一些题目,在长剖之外也可以思考一下这个做法!
ARC087F Squirrel Migration
这题就是环排列最优化,以前在 nfls 做过一个排列最优化的难度更大,记得写过啊。。。
所以就很简单了,先猜答案最大值:对每条边考虑,次数肯定是 \(\min\{sz_i,n-sz_i\}\)。于是以重心定根然后答案就是每条边的 \(sz_i\) 之和。
然后再思考一下什么样的排列(实际上就是左部和右部都为 \(1\sim n\) 的二分图匹配)能取到这个值。
那相当于是你不能有一条匹配的边,连接的两个点在同一边子树。然后思考一下发现重心和谁匹配都无所谓,和自己都行。。
接下来看到 \(n\le 5000\) 就大大方方容斥了,对每个子树都选一些点出来连向子树内部,跑个背包带走了。
ARC115F Migration
兄弟,这个我哪会啊???????????
兄弟,这个我要是做过 NOIP T3 就轻松拿下了,唉。。。。
还是二分一手答案,然后发现还是做不明白,主要是我们可以让点拐出去走到外面让权值更小再让其他人动,这个太复杂了,兄弟。
然后考虑操作是可逆的所以我们如果存在一个局面使得起点和终点都能走到那么就等价于起点和终点能走到。
那很容易想到就选最小的局面,如果有多个就让字典序最小。然后比较两个局面是否相同就行。现在就变成了一个最优化而非可达性问题,很显然我们自由很多。只用考虑在二分上界不被超过的情况下最小化权值。
如果只有一个点那就是经典重构树,向上走到一个最浅的点再向下走到子树最大值。所以多个点的话开始先把大家移动到重构树子树内的最小值。接下来如果想让权值变小就总是经历这样一个过程:先走过一个更大的点,再走到一个更小的点。
这种题还有点 exchange argument 的味道,可以看成我们需要先留出 \(a_i\) 的支出然后才能获得 \(b_i\) 的收益(\(a_i\le b_i\)),然后我们显然会先做 \(a_i\) 小的,因为它们更容易实现且收益总是正的。
所以只需要对每个点 \(x\) 求一个点 \(y\),使得 \(v_y\le v_x\) 且路径上的最大值最小。可以很容易在重构树的结构上 \(O(n)\) 维护出来。然后就有 \(O(n)\) 条转化关系:我们按照路径上的最大值这个参数从小到大排序,暴力检查每个棋子能否使用这条转化关系就能得到一个 \(O(nk\log v)\) 的做法,足以通过此题。
GD 省集加强到了 \(2\times 10^5\),大家觉得呢?其实这部分反而不难。
就是有这样一个性质:若 \(a\rightarrow b\) 可行且 \(b\rightarrow c\) 也可行肯定后者的那个代价更大,否则你直接就 \(a\rightarrow c\) 了。所以当我们尝试一条移动关系 \(x\rightarrow y\) 时,以后肯定不会再有某个棋子转化成 \(x\) 了,你拿个 dsu 把此时所有在 \(x\) 的棋子合并成一个就行了。堂堂通过。
ARC138E Decreasing Subsequence
当时场上做了这个题啊,做半天也没做出来,还看不懂那个神秘题解。其实现在过了也没看懂那个神秘题解。
考虑整个序列是越往后取值越宽松的,但你选出来的子序列越靠后限制越严。我们枚举选出的子序列的第一个位置 \(p\),然后假设 \(a_p=x\) 那么在 \([1,x)\) 里还剩的取值(剩哪些无所谓,我们只关注个数)任意选 \(k-1\) 个作为剩下的选出的那些位置的取值即可。
那么就做一个 dp:\(f(i,j)\) 表示考虑完前 \(i\) 个位置,然后 \([1,i]\) 还剩下 \(j\) 个值可以选的方案数。那么后面这部分怎么做?因为你正着做不可避免要区分这个不在子序列的和在子序列的就得记录两个数目。
回归最朴素的那个问题:就是有多少个好的序列,除了一眼看出来的正着 dp,有没有契合后缀的倒着 dp 的形式?
发现还真有:设 \(g(i,j)\) 表示还有 \(j\) 个位置选了数还没有填,就行了。这个过程很自然地结合到要问的东西上:假设后半部分还剩 \(j\) 个位置选了数没有填,那么我们任意选 \(k-1\) 个位置作为下降子序列所在位置即可。所以得到一个 \(O(n^2)\) dp 后 \(n^3\) 计算的方法:枚举 \(i\) 和前半部分剩下的 \(cnt\) 和后半部分的空位数即可。
能不能优化?考虑把从后往前的过程一口气做掉,也就是 dp 过程分为三个阶段:后-\(p_1\)-前。用 g(i,j,0/1)$ 表示状态,前两维意义不变,第三维表示我们是否已经确定了 \(p_1\) 的出现,然后即可 \(O(n^2)\) 计算。
CF1930G Prefix Counting
一个点能加入序列需要满足两个条件:
-
他是根到自身的路径最大值。
-
在 dfs 顺序中,考虑每个祖先 \(p\),\(p\) 的其他子树若先于 \(u\) 访问,则其最大值都要小于 \(p\)。
因此考虑对于一个点 \(u\) 而言,我们把其子树按照子树内最大值排序,然后,一定是按照这个顺序走若干个子树,把剩余子树都放到最大的那颗后面等效于丢掉。(所以最大的那颗子树是必走的)
解法一:
考虑设计这样一个 dp:设 \(dp(u,k)\) 是走进了 \(u\) 子树且之前之前的前缀最大值为 \(k\) 的时候能走出多少种序列,我们不计数空集。倒序考虑每个子树即可完成合并。时空复杂度 \(O(n\log n)\),细节很多,还卡空间,别写。
解法二:
这个很牛啊!考虑就是最硬做的,我们先按照刚才那个子树最大值的顺序把 dfs 序搞出来然后最后的前缀最大值序列一定是它的子序列。那就考虑最经典的设 \(f_u\) 是以点 \(u\) 结尾的子序列数,最后 \(f_n\) 就是答案。显然 \(f_1=1\)。
然后 \(f_u\) 能不能转移到 \(f_v\) 呢?根据我们刚才的说法就是,你先考虑 \(u\) 是 \(v\) 的祖先的情况,那你其实只要满足 \(u\sim v\) 的路径上没更大的就赢了。然后考虑那种 \(u\) 往上回溯若干步再去 \(v\) 的情况,考虑 \(t=lca(u,v)\),那么 \(u\) 必须是 \(t\) 节点的 \(u\) 那颗子树的最大值。
所以在 dfs 的过程中维护一个 bit:把根到当前路径的 dp 值放进对应下标,dfs 到一个点的时候,扫过一个子树就把子树最大值的对应 dp 值也扔进去。然后 \(dp(u)\) 的计算就是:若 \(u\) 不是根到路径的最大值肯定为 \(0\),否则设根到路径次大值为 \(u'\),那么编号在 \((u',u)\) 中的那些 dp 值就是我们要的,查一下 bit 即可,时间复杂度 \(O(n\log n)\)。这个是真牛。。。
JOISC2024 ski2
这个也牛完了啊。
首先考虑把序列按照 \(h\) 这个维度排列开然后在此基础上顺序扫描搞点插头 dp 之类的。
唉,首先有个问题就是 \(h\) 很大你按这个顺序搞第一维都炸了。容易看出如果我们想让 \(i\) 连 \(j\) 那调整到 \(h_j+1\) 就够了,但是如果还有 \(k\) 要连 \(i\),还有 \(p\) 要连 \(k\),那最后可能取到的 \(h\) 值不是有至少 \(O(n^2)\) 个了?
事实上还真是,可能真有这种情况发生。但是我们可以说明,如果一个人的 \(h\) 增加了,就至多会有一个人当他的儿子(用那个免费的名额):可以反证一下,这一步太智慧了,唉。。。
然后首先你从前往后扫的过程中得记录一下啥,还要继续增高的人的个数,以及还剩的名额数。然后你就真的可以加速了,因为会增高的人不会自己增名额,所以如果一整段值域里都没有人的 \(h\) 出现,那你知道一开始的要增高的人的人数和还剩的名额数,接下来的变化你贪心匹配就好了,都容易 \(O(1)\) 计算的。只有在 h_i/$ 这些位置会出现一个位置停住不动新增名额的情况,所以就容易设计出一个 \(O(n^3)\) 的状态。转移 \(O(n)\) 是因为需要枚举 \(c\) 最小那个哥们新增了几个名额,但你也发现不需要,类似完全背包那样转就行了。还有根节点的问题,所以第一次在某个高度有人暂停(显然一定是某个 \(h_i\))的时候就需要特判一下。
时间复杂度 \(O(n^3)\)。
USACO 2024 FEB Minimum Sum of Maximums
更是牛完了???我真的不会这种题啊。
先考虑 \(k=0\) 那可以猜到就是顺序排,能证明不?
顺序排很容易让我们联想到差的绝对值最小,然后 \(\max\{a,b\}=\frac{a+b+|a-b|}{2}\) 所以我们确实就是在最小化差的绝对值。然后考虑 \(k\gt 0\) 的话,假如我已经知道了每一段的数集,不难证明也一定是顺序排的。所以不妨设两侧的值分别为 \(L\le R\) 贡献就是 \(|mn-L|+|mx-R|+(mx-mn)\)。
然后现在有个问题就是我们每个空填的个数是确定的,这个特点非常的棘手,你告诉我你怎么 dp.jpg。而且这导致我们有个思想就是我们尽可能一次就把一个段的轮廓确定,也就是 \(mn,mx\)。
然后 dp 不了的时候就要找性质,尤其是这种最优化题。你会发现每个段的值域 \([mn,mx]\) 可以通过调整做到要么包含要么不交也就是大家最爱的树形结构,然后就很舒服了。因为你不会出现,我已经钦定了一个 \([l,r]\) 给一个段,但是内部有一些数要给一个外面的段(当然内部可能有一些数会给完全包含在里面的段)。
于是设 \(dp(l,r,S)\) 是我们已经用了排序后的 \([l,r]\) 中的这些值然后填满了 \(S\) 中的所有位置。转移还是有点复杂的。
第一种情况是 \(l/r\) 有一个没有用到,那么就直接 \(dp(l+1,r,S)\) 或者 \(dp(l,r-1,S)\)。
第二种情况是都被同一个段用了,那么转移进 \(dp(l+1,r-1,S')\),不需要考虑这个段剩下的人取谁,只要 \([l,r]\) 长度足够,把 \(S'\) 用过的哥们去掉剩下的随便哪些数给这一段都行。
第三种情况是被两个不同段用了:那枚举一下分界点 \(p\) 和子集 \(T\) 转移到 \(dp(l,p,T)\) 和 \(dp(p+1,r,S^T)\) 即可。这样复杂度是 \(O(n^32^k)\) 的有点超模。。。。。但你发现一个事情就是这种情况下一定是要满足 \(r-l+1\) 就是 \(S\) 的所有段长之和的,不然不就等于你在内部留了空位给外面的,但我们前面说过了这种情况一定不会发生的。
所以复杂度 \(O(n^23^k)\) 拿下了。
USACO2024 FEB Infinite Adventure
这个题也特别牛啊,兄弟!
如果 \(T_i\) 全部相同我们直接大力倍增就是,设 \(f(i,j,k)\) 表示若 \(t\bmod T_i\equiv j\) 此时从 \(i\) 开始走 \(2^k\) 步会到谁。但是如果 \(T_i\) 不同会有一个问题,你从 \(T_i\) 大的走到 \(T_i\) 小的,只要你知道 \(t\bmod T_i\),就真的知道 \(t\bmod T_j\) ;但是反过来就不一定了。
于是想到一个神来之笔:设 \(g(i,j)\) 表示从 \((i,j)\) 开始走第一次走到的 \(T\gt T_i\) 的点。考虑处理出来 \(g\) 以后怎么办?我们定义一个递归过程 \(F(u,x,k)\) 表示从 \((u,x)\) 开始走 \(k\) 步求终点。首先我们不断尝试走 \(g\),这个过程是 \(O(\log n)\) 的,然后我们接下来不管怎么走,\(T\) 都不会比 \(T_u\) 大。如果 \(T\) 一定比 \(T_u\) 小就很舒服因为你可以直接递归。所以考虑再设一个 \(f(i,j)\) 表示从 \((i,j)\) 开始走第一次走到的 \(T\ge T_i\) 的点,然后我们对 \(f(i,j)\) 再维护一下倍增信息。这样再花费 \(O(\log k)\) 的代价,再走到一个点 \(u\)。然后我们就能保证之后走到的点永远满足 \(T\lt T_u\)。所以就在 \(O(q\log^2)\) 的时间内完成了单次询问。
再考虑预处理 \(g/f\)。显然是按照 \(k\) 的大小从小到大考虑每个 \(T_i=2^k\) 的点。然后先处理 \(f(i,j)\),然后维护其倍增信息,最后再算 \(g\) 是很容易的。然后 \(f\) 其实也很好利用之前的信息算,你走一步,接下来就顺利成章了。
然后就在 \(O((n+q)\log^2)\) 的时间内拿下了。
ARC111F Do you like query problems?
唉为啥这个题被卡了。。
方便起见我们先转成算期望,然后根据线性性考虑每个位置 \(x\) 的期望贡献。然后还能做的更牛一点:就是枚举一个 \(i\in [1,q]\) 表示说第 \(i\) 次是一个包含 \(x\) 的询问,此时 \(x\) 的期望值是多少。
首先考虑 \(n=1\) 的情况,也就是每次区间都是有效操作的情况。
很容易注意到除了 \(0\) 以外,取到每一个 \([1,m)\) 之间的数都是相同的。
所以不妨设 \(p(t)\) 是 \(t\) 次“修改”操作以后变量非 \(0\) 的概率,初始 \(p(0)=0\),考虑 \(p(t-1)\rightarrow p(t)\) 的转移,则 \(p(t)\) 显然可以写成 \(Kp(t-1)+B\) 的形式。如果我们把 \(p(t)\) 换一下定义,改成 \(t\) 次操作(也就是有一定概率是无关变量取值的查询操作)后变量非 \(0\) 的概率,一样可以将 \(p(t)\) 写成 \(Kp(t-1)+B\) 的形式。进一步,如果再加上一个概率,表示有时候你的 \([l,r]\) 压根就不包含 \(x\)(在 \(n\gt 1\) 的时候),我们还是能把 \(p(t)\) 写成 \(Kp(t-1)+B\) 的形式。显然 \(K,B\) 只和 \(x\) 有关。所以考虑枚举 \(x\),然后枚举一下 \(i\),把类似 \(\frac{mf(i)}{2}\) 的东西加进答案就行了。
然后注意到 \(p(t)\) 可以写成等比数列求和的形式:\(B(\sum_{i\lt k}K^i)\),然后再对 \(p(t)\) 求前缀和又是一次等比数列求和(其实等比数列的 \(c\) 次前缀和都可以 \(O(c\log)\) 求吧)。所以就在 \(O(n\log)\) 的时间内拿下了。
ARC177F Two Airlines
这个题就是典型的 F 不如 E。做的时候前面的都秒了,真想不到最后一步啊,兄弟。
每个人的移动轨迹一定形如先向左一段再向右一段。称前者为 \(A\) 段后者为 \(B\) 段。容易看出 \(B\) 段就是传递宝藏的路线,每个人的 \(B\) 段长度拼起来应该恰好长度为 \(L\) 且覆盖整个链;而 \(A\) 段就是他们各自为了走到 \(B\) 段起点而进行的赶路。
于是有显然的 dp:设 \(dp(i,j,k,0/1)\) 表示当前宝藏位于 \(i\) 点,然后拖着它的那个正在走 \(B\) 段的人是哪种类型的。然后两种类型分别有多少个人使得:他们的 \(A\) 段路线从 \(\gt i\) 的位置出发,在 \(\le i\) 的位置结束。
转移很简单:首先讨论一下走到 \(i+1\) 后当前这个人的 \(B\) 段是否就停止了,然后 \(j,k\) 肯定是能和 \(i+1\) 处的起点匹配就尽量贪心匹配。于是可以 \(O(1)\) 转移,复杂度 \(O(Lm^2)\)。
我们断言 \(j,k\) 的数量级不会很大:事实上 \(j,k\)f 都是 \(O(\log L)\) 量级的。我们以 \(j\) 为例进行说明:你考虑假设某个时刻有 \(j\) 个第一类的人需要从 \(\gt i\) 的位置向左走到 \(\le i\) 的位置。考虑按照 \(x\) 坐标编号为 \(1,2,3,...,x\)。因为我们知道这 \(x\) 个人的 \(A\) 段路径全部有交(位于 \(i\) 处),所以我们想一下,如果删除 \(c_2\),让 \(c_1\) 的 \(B\) 段路径增长,那么代价的变化是什么?发现就是说,会多出来的只有中间那一段(由第二类型的人走的 \(B\) 段)的第二类边的个数。但是从 \(2\sim x-1\) 号来看,他们和下一个同类人之间的 \(B\) 段路径也会夹杂一段第二类型的 \(B\) 路径,而这些路径的 第二类边都从原来的要走一次变成了不用走。所以这些部分的长度之和必须小于第一段的那个长度,然后同样的用删除 \(3\) 来做假设。。。然后就能发现 \(c_{x-1}\gt c_{x}\),\(c_{x-2}\gt c_{x-1}+c_{x}\),重复以往就能推得 \(j\le \log L\)。
于是修改一下刚才 dp 的上界就做到 \(O(L\log^2 L)\) 了。。。。
qoj7677 Easy Diameter Problem
本周必做
考虑这样一个删直径端点的过程也太蛋疼了:我们考虑所有直径中心必交于中点。不妨让每条边上都新增一个新点,然后我们的直径永远都在点上。现在假设中点位于 \(r\),对于其子树 \(v_1,v_2,...,v_k\) 都有至少一个距离为 \(len\)(\(len\) 为直径的一半)的点存在(\(k\ge 2\)),那么:
我们会不断删这些距离为 \(len\) 的点,直到仅剩一颗子树 \(v_i\) 还有余留。此时将 \(r\) 改为 \(v_i\) 然后重复这个过程。
问题在于此时 \(v_i\) 这边也会删一些点,但是我们不知道删哪些且并不是所有点都删。不妨接下来再走一步:令 \(r'=v_i\)。
此时考虑把 \(r'\) 的若干子树删完后继续移动 \(r'\):如果移动回了 \(r\) 说明这个时候我们已经把 \(r'\) 这边的点删完了,然后 \(r\) 子树(以 \(r'\) 为根)就出现了新的一些点不知道在何时被删除;如果又移动到了一个新的 \(r''\),说明我们又把其他子树(\(r'\) 的其他儿子,以及 \(r\))的点删完了,然后 \(r''\) 这里的点就是不知道什么时候删的。
总结一下,我们会出现这样一个情况:在我们已经确定的删除序列中,结尾若干个数的中间还能插入一些未删除的数。所以设 \(dp(x,y,dis,num)\) 表示说以 \(x\) 为直径中心,上一步的中心是 \(y\),然后只保留距离 \(\le dis\) 的点,\(num\) 就是已经确定的删除序列中结尾有多少个数中间还能自由插空的。
转移还需要下一步中心枚举转移到哪边,如果转移到 \(y\) 的话还要额外枚举多少个是放在这 \(num\) 个后面的,作为新的 \(num\)。但总复杂度可以分析出 \(O(n^3)\) 倒不是难点。感觉这题能编出多项式就很牛了。
CCO2021 Through Another Maze Darkly
嗨呀经典题呀,大家最喜欢的一集
先考虑链的情况,发现不对啊?考虑这样一个:< < < < > ...的链,那你会走过去再走回来嘛,然后这个时候你发现变成了 < < < < < ...;等你走到头再回来,然后后面的过程就是不断的向右走到底再向左走到底再向右走到底呃。。。
再研究一下树的过程,是不是也是,你最多走 \(n\) 趟,然后回到 \(1\),然后接下来就是在 dfs 啊?就是得到一个长度为 \(2n-2\) 的序列也就是欧拉序。。
然后你发现只要你进入了一个节点,再从它这里出来,那么他的指针就会指向第一个儿子的这个状态(我们认为先往指针方向走然后再调整该指针),但是你前面的几次 dfs 不能进入所有的节点,因为有些点一开始指向的不是第一个儿子,或者直接指向父亲了。
所以你每一步 dfs 出的就是最后那个完整欧拉序的一个子序列。然后每一次 dfs 的基础上都在上一个序列上激活了若干个位置。所以拿个可持久化数组维护一下每一次 dfs 的序列形态,然后询问的时候先二分到哪一次 dfs,再在这个数组上二分就行,所以写个主席树拿下。时间复杂度 \(O((n+q)\log n)\)。
ARC112E Cigar Box
首先要注意到,一个数若被选中移动了多次则只关心最后一次放在开头还是结尾。然后我们容易看出没有被选过的位置一定构成 \(a\) 的一个上升子段。
-
若至少有一个数没有被选过,设该区间为 \([l,r]\),现在要把 \(m\) 次操作平均分配给左右两边,枚举左边用了 \(x\) 次右边就用了 \(m-x\) 次,然后两边方案独立计算最后组合数合并即可。考虑一边的话可以设计出这样一个递推:设 \(f(x,y)\) 是 \(y\) 次操作放给这 \(x\) 个数,则转移显然为 \(f(x,y)=xf(x-1,y)+f(x-1,y-1)\)。朴素做是三方的,枚举 \(x,l\) 以后所有合法的 \(f(n-r,m-x)\) 可以用后缀和预处理出来,做到 \(O(nm)\) 的复杂度。
-
若所有数都被选过,从前往后删除每个操作,设 \(x\) 是最早的一个位置,使得此时后该位置不再被操作。然后再设此时是第 \(y\) 步,现在还要把 \(m-y\) 个操作分给左右两边,还要确切知道左右两边分别选了多少个操作。看上去是 \((nm^2)\) 的难以优化。但考虑 \(x\) 这个位置具体是谁并不重要,考虑先交换求和顺序,枚举一下 \(y\),然后把左右两边的 dp 顺序放在一起,计算出一个 \(f'(n-1,m-y)\) 就是所有的 \(x\) 的答案的总和。于是又在 \(O(nm)\) 的时间内拿下。
ARC114E Paper Cutting 2
一句话题解:考虑一维情况等价于随机一个切线的排列然后只切有意义的那些刀。于是考虑枚举一个切线计算轮到他时他依旧有效的概率。不妨设这个切线位置在 \(x\lt l\) 则 \((x,r]\) 之间的切线都不能切。若有 \(cnt\) 个干扰项则显然概率就是 \(\frac{1}{cnt+1}\),然后做完了。
JOISC2021 逃跑路线
记 \((u,t)\) 是位于点 \(u\) 且时刻为 \(t\) 的一个点(\(t\) 在 \([0,\infty)\) 意义下)。
然后最朴素的暴力:我们可以对一个 \((u,t)\) 在 \(O(n^2+m)\) 的时间内跑出到每个点的最短时间。
当然不是让你 \(O(qn^2)\) 过的。考虑优化。
如果我们经过了不止一天,就很容易:考虑枚举一个点 \(w\) 使得 \(u\rightarrow w\) 是第一天的全部路程然后 \(w\rightarrow v\) 是后面开始的路程。那么后半段很好算啊,就是 \((w,0)\) 为起点的单源最短路。
前半段是问你能否在一天内从 \((u,t)\) 走到 \((w,0)\) 啊,这个肯定是让你倒着跑的,相当于要做这个东西:
给一个状态 \((u,t)\) 对每个点求出出发时间最晚是多少才能到达 \((u,t)\),倒着跑 dij 就能同样 \(O(n^2+m)\) 拿下。然后我们发现我们甚至可以对每个 \((u,v)\) 预处理然后二分一下。。。这部分是 \(O(\log)\) 单次的。
然后考虑一天内的,这个时候就没有什么 \((x,0)\) 或者 \((x,S)\) 的特殊点给你蹭了。然后就是大家都猜到的什么有意义时刻不会太多,那么是怎么分析的呢?假设你找到了一条路径,你不断让出发时间加一一定能顶到一条边 \((x,y)\)。那你不妨分成两段来看:\(u\rightarrow x\) 和 \(y\rightarrow v\) 嘛。
后半段还是你固定从 \((y,C)\) 那个时刻出发到 \(v\),所以是要跑 \(O(m)\) 次固定起点的最短路。
前半段相当于是从 \((x,C-L)\) 做反跑的最短路,和前面一样的。
然后可以在四方的预处理和 \(O(\log)\) 的询问中拿下。
ARC101F Robots and Exits
对于每个机器人找到左右两侧的第一个出口,然后设距离分别为 \(L,R\),把他对应到数轴上的区间 \([-L,R]\) 上。
对于一个移动路径我们只关注向左走的历史最大值和向右走的历史最大值,分别记作 \(x,y\),刚好对应了 \(L/R\) 的两个维度。我们显然就是不断拓大 \(x\) 或者不断拓大 \(y\)。
建图:对于左半边,从 \(-x\) 连向 \(-(x+1)\),对右半边,从 \(x\) 连向 \((x+1)\),对于区间 \([-L,R]\),若我们选择这个机器人从左边出去,就从左侧的 \(-L\) 连向右侧的 \(R\),否则就反过来连。然后只要这张图是个 DAG 我们就能找到一个路径满足这些机器人是从我们想要的出口出去的。怎么快速判断图是不是 DAG 呢?
我们发现任意两个区间都有交(都包含 \(0\)),当是严格包含关系的时候不会互相产生矛盾。但如果是相交不包含的情况就有可能会出事:设 \(-L_1\lt -L_2,R_1\lt R_2\),则当 \(-L_1\) 连向 \(R_1\),同时 \(R_2\) 连向 \(-L_2\) 的时候会成环。然后考虑一些边界情况比如 \(L/R\) 有相同的时候咋做,首先可以去重 \(L,R\) 都是相等的区间,然后发现 \(L_1=L_2,R_1\lt R_2\) 的时候矛盾产生在 \(-L_1\rightarrow R_1\) 且 \(R_2\rightarrow L_2\) 的时候,\(L_1\lt L_2,R_1=R_2\) 不多说了。
总而言之,把区间按照 \((-L,R)\) 为第一、第二关键字升序排序,则我们从前往后考虑,那么只关心所有选择了 \(-L\rightarrow R\) 的区间里 \(R\) 最小的那个。可以简单用 dp 维护,bit 优化转移。时间复杂度 \(O(n\log n)\)。
ARC100F Colorful Sequences
没有 101F 难。
考虑枚举一个 \([i,i+m)\) 强制这 \(m\) 个位置和 \(A\) 匹配然后算合法序列方案数。发现若 \(A\) 中数不全相同,左侧右侧方案数就是独立的,很容易 \(O(nk)\) 去算。所以只用考虑 \(A\) 中元素互不相同的情况。
显然把 \(A\) 换成任意一个长度为 \(m\) 的元素互不相同的序列答案都是一样的,根据对称性我们只要对所有序列的所有长度为 \(m\) 的互不相同的子段求和再除以方案数即可。
NOI2017 蔬菜
考虑如果天数确定可以倒着做,把每个蔬菜放在失效的日期,然后你倒着做就不用考虑要把快坏掉的蔬菜提前卖的事情,只用贪心地把当前没卖的最贵的蔬菜在这天卖了就行。然后数据结构优化一下这个过程其实能拿 80 分了。
然后考虑从第 \((i+1)\) 天的答案调整到第 \(i\) 天的。那你发现维护一个集合表示当前的选择方案。如果这个集合的大小不超过 \(i\times m\) 那就不用调整,否则你直接删最小的删到还剩 \(i\times m\) 个就对了。。。
qoj8526 Polygon II
不是,兄弟,这个我哪会啊?????
先转化条件:合法当且仅当每一条线段都小于其他线段的长度和。由于是连续概率所以有些地方的取等你加不加是不改变概率的。
自然想到枚举最长的一条线段 \(x\) 计算他比其他线段加起来都长的概率。
先考虑 \(a_i=0\) 的情况:此时相当于有 \(n\) 个 \([0,1)\) 变量 \(a\),需要满足:
这个形式不好看,我们取反一下:
注意到 \(a_x\) 和 \(1-a_x\) 的概率分布完全相同的,所以你可以依旧把右侧看成 \(n\) 个 \([0,1)\) 变量,求他们的和不超过 \(k\) 的方案数,其中 \(k\) 是任意整数。
然后可以想到说容斥去解决 \(1\) 的上界,但是我们很难去解释概率这个东西了。
考虑这样一个想法:就是,用一个点 \((a_1,a_2,...,a_n)\) 来表示一个方案,那么 \(a_i\in [0,1)\) 等价于点集构成一个超立方体,你要求所有满足 \(\sum a_i\le 1\) 的点的体积。
那么考虑对坐标容斥:钦定有 \(y\) 个维度是 \(\ge 1\) 的,然后算 \(n\) 维的点和为 \(k-y\) 的体积。
那也就是 \(\sum a_i\le K(=k-y)\),考虑转前缀和:那么变成 \(0\le b_1\le b_2\le ... \le b_n\le K\)。如果忽略 \(b\) 升序的限制那么答案就是 \(K^n\)。现在带了直接除以 \(n!\) 即可(你可以放心忽略相等的体积)。
再考虑那个问题如果是整数怎么做?我们数位 dp 一下就好了。需要记录一下进位。
那么把整数和小数部分分开来做,初始化的时候使用我们刚才提到的东西就行了。时间复杂度 \(O(n^2\log n)\)。
qoj8521 Pattern Search II
这个题还行,没那么超模。
容易观测到你可以找到一个长度为 \(O(n)\) 的 \(S_k\) 包含你的 \(S\) 作为答案。
那就可以大大方方 \(O(n^2)\) dp 了。
然后这个 fib 串有个性质就是你可以像线段树那样拆分区间,拆分出来的区间数还是 \(O(\log)\) 的。那每一个区间都是一个 fib 串所以你只要预处理一个 \(O(n\log)\) 的 DP 然后在这个 fib 树上按顺序匹配一下就能加速匹配过程了。
qoj8522 Waterfall Matrix
一眼保序回归 \(L_1\) 模板题,考虑把所有出现过的值拉出来然后跑整体二分。现在就是说你要做一个类似 dp 的东西。
你考虑他这个划分,肯定是特别有规律的,因为是个矩阵。具体而言肯定是个阶梯型的轮廓线,所以你就可以 \(O(n\log n)\) 地完成一次 dp,这里要用线段树优化一下。
然后因为你是要知道方案的,所以需要把线段树可持久化一下。算上整体二分复杂度是 \(O(n\log^2 n)\)。
gym104819F Four K3
这题很牛魔啊。。
考虑枚举中间那个三元环然后算答案,那相当于你要统计每个边在多少个三元环上,这个很容易算三元环个数的时候算出来。设第 \(i\) 条边在 \(a_i\) 个三元环上然后你加上 \((a_x-1)(a_y-1)(a_z-1)\),这个看着很对但是你注意到可能有一个点共同和 \(x/y/z\) 的多个人构成三元环,相当于多算了一些方案,比如你按照这个去算 K4 的话答案应为 \(0\) 但算出来不是。
那你考虑三条边 \(x,y,z\),然后条件是 \(x/y\),\(y/z\),\(x/z\) 都不和同一个点构成三元环。容斥一下,发现只要算两种情况:K4 以及 K4 拼上一个三元环。
前者大家都会算吧,后者你只要统计一条边在多少个 K4 里就行了。
然后算 K4 还是记录一下吧,就是你按照算三元环那个方式给图重新定向然后这个时候每个点的出度就是 \(O(\sqrt{m})\) 的,然后枚举 K4 里度数最小的那个点,然后就是 \(O(\sqrt m)\) 规模的三元环计数,每个点的出度也是 \(O(\sqrt{m})\) 的所以不能使用我们平时求三元环的做法。使用 bitset 做到 \(O(\frac{m}{w})\),总复杂度就是 \(O(\frac{m^2}{w})\)。
qoj8089 Flaaffy
感觉 Day2T1 难度。
首先容易设计出一个区间 dp 并且这个问题我们也很难不做区间 dp。但是观测到答案很小因此可以考虑换维。
但是这个区间 dp 你要设计的比较仔细:会发现除了第一次询问以外,假设你确定答案位于 \([L,R]\)(特判 \(L=R\)),其余时刻当前的数 \(x\) 要么 \(x=L-1\) 要么 \(x=R+1\)。所以至少状态数是 \(O(n^2)\) 的,就设 \(f(L,R)\) 和 \(g(L,R)\) 表示两种情况就可以。
可以观测到答案不是很大,令 \(m=50\) 是够的。并且若 \(f(L,R)\) 能在 \(x\) 步内问出来则 \(f(L,R-1)\) 也一定可以。所以交换答案和一维,设 \(f(L,x)\) 和 \(g(x,R)\) 即可。这样复杂度从 \(O(n^3)\) 降低到了 \(O(n^2m)\) 并且状态数已经可以接受了。
现在优化转移:我们肯定从小往大枚举 \(x\) 然后去计算 \(f(L,x)\) 和 \(g(R,x)\),不妨以 \(f(L)\) 的计算为例。假设调整到 \(p\)(不需要保证 \(p\gt L\),因为如果 \(p\le L\) 一定不优),则贡献为 \(diff(L,p)+1\),其中 \(diff(L,p)\) 是两者有多少位不同。令 \(y=x-diff(L,p)-1\),同时需要满足 \(g(p,y)\le L+1\),然后将 \(f(p,y)\) 去和 \(f(L)\) 取较大值。
显然 \(diff(p,L)\in [0,5]\),所以我们计算 \(f(x)\) 的时候只有 \(O(n)\) 个之前的 \(f/g(p,y)\) 是有用的。我们把所有的 \((p,y)\) 按照 \(g(p,y)\) 去排序,然后从小到大枚举 \(L\)。这样满足 \(g(p,y)\le L+1\) 的就一定是一个不断增长的前缀,可以用双指针维护,动态地加入一些 \(f(p,y)\) 的值。
还剩一个问题是你的 \((p,y)\) 不是任意贡献给每一个 \(f(L,x)\) 的,还得保证 \(diff(p,L)+1=x-y\)。
现在考虑把这个五位十进制数变成五位十一进制数,新增一个数码 ?
。然后我们加入一个 \(f(p,y)\) 的时候,考虑任意地选择 \([0,5]\) 的一个大小为 \(x-y-1\) 的子集 \(S\),把 \(p\) 中对应位置换成问号得到 \(p'\)。维护一个桶 \(h\),把 \(g(p,y)\) 的值更新到所有 \(h(p')\) 上。计算 \(f(L,x)\) 的时候同样地枚举一个任意的 \(S\),把对应位置换成问号得到 \(L'\),然后查询 \(h(L')\) 即可。
然后在 \(O(nm(2^k+\log n))\) 的复杂度内解决了本题,其中 \(k=5\)。
nfls 6.28 T2 Arcturus
T1 就是 Flaaffy。
入手点是最暴力的 \(O(m)\) dp:令 \(a,b\) 是位置 \(i\) 之前的黑点白点数量。再令 \(f_i\) 是所有 \(a=i\) 的位置的 dp 值之和,再令 \(g_i\) 是所有 \(b=i\) 的位置的 dp 值之和。那显然 \(dp(i)=f_{a-x}+g_{b-y}\)。然后再分别加到 \(f_a\) 和 \(g_b\) 上。
然后发现 \(f,g\) 是可以滚动的,就是说你确定了 \(f_i\) 以后 \(f_{i-x}\) 就不需要了。
然后模拟一下一个连续段对 dp 值的影响发现是很容易维护的,最后只需要你区间加区间求和就行了,直接无脑动态开点线段树就 \(O(n\log V)\) 了。
qoj7405 Stone Game
令 \(v_a\) 表示 \(a\) 有多少个因子 \(2\)。不妨设 \(v_a\ge v_b\)。当 \(v_a=v_b\) 时,若 \(v_a\) 为奇数则先手胜否则后手胜,因为一定会从 \((v_a,v_b)\) 转成 \((v_a-1,v_b-1)\)。
当 \(v_a\gt v_b\) 的时候,若 \(v_a-v_b\ge 2\),则我们可以变成 \((v_a-1,v_b)\) 或者 \((v_b-1,v_b-1)\),所以显然若 \(v_b\) 是偶数则先手胜,否则两人会轮流交替去取 \(v_a\) 那边,直到来到 \((v_b+1,v_b)\)。
当 \(v_a=v_b+1\) 时:要么变成 \((v_a-1,v_b+1)\) 要么变成 \((v_b-1,v_b-1)\)。之前已经说了 \(v_b\) 是偶数则先手胜,而 \(v_b\) 是奇数的时候就会陷入循环导致平局。
这样我们找到了胜平负的各自的充要条件,后面的计算是平凡的。
qoj7406 Longest Lyndon Prefix
首先 \(s[l,r]\) 是 lyndon 的一个必要条件是,把 \(s_{l}\sim s_{r}\) 按字典序排,\(suf(l+1)\sim suf(r)\) 都出现在 \(suf(l)\) 后面。
然后我们找到最小的 \(r\) 使得 \(suf(r+1)\gt suf(l)\) 然后 \([l,r]\) 就是答案。。。
反证一下:假设有个 \(x\in (l,r]\) 满足 \(suf(x)\gt suf(l)\) 但是在 \([l,r]\) 出表现不出来。那就说明 \(s[l,r]\) 有一个长度为 \(x=r-p+1\) 的 border,所以比较 \(suf(l)\) 和 \(suf(p)\) 的大小都是在比较 \(suf(l+p)\) 和 \(suf(r+1)\) 的大小,所以必定有 \(suf(r+1)\gt suf(l+p)\gt suf(l)\) 存在,矛盾。
然后做完了啊。
qoj7404 Back and Forth
这个题好难啊。。
重点肯定是你得会一个多项式做法:考虑研究一下路径的形态,肯定是一条从 \(s\) 到 \(t\) 的链,关键是回来的路径,可能会成环。就是 \(t\) 先到一个链上的点 \(x\),然后这个点 \(x\) 可以沿着链走走到 \(y\),然后 \(y\) 再走到链上一个更靠前的点 \(x'\),重复这个过程。。。
那我们就可以按照这个 \((x,y)\) 来设计状态。所以是 \(O(n^2)\) 个状态,但是有环所以需要跑 dij,这样是 \(O(n^4)\)。
发现转移两个维度是独立的,所以可以开一个中间状态辅助一下转移,就变成 \(O(n^3\log n)\) 了。。
AGC061E Increment or XOR
太牛了吧???正常人类如何做出这个题目啊。
首先如果一次加法操作能影响到从低往高第 \(i\) 位的取值那一定说明在这次加法之前前面 \(i-1\) 位都是 \(1\),然后发生了进位。
如果没有进位,xor运算的特性是每位独立的,很容易按位分开来考虑(记录每个 xor 操作出现的奇偶性即可);如果有进位,我们已发现必定存在一个中间态:也就是最低的若干位全部是 \(0\) 然后进给高位一个 \(1\) 的中间状态。
再来考虑最高位(因为不用再去考虑最高位进位的影响,所以考虑最高位的情况最简单):如果前面的位没有给他进位,那么我们相当于递归进了一个子问题,在子问题中,只需要保证每个 xor 运算操作使用次数的奇偶性正确(用来满足最高位的取值)即可。那么如果进位了呢?以刚才提到的中间状态作为分界点,在这之前的 xor 操作需要作用到最高位过后不能令其变为 \(1\)(否则加上低位给的进位就会 \(1+1=2\))。那么在这次进位操作之后呢?我们知道低位全部为 \(0\),但是有没有可能会再进行若干次加法操作使得又产生一次进位?然后在这些加法操作之间因为 xor 的存在导致最高位又变回了 \(0\),加上了进位以后变成了 \(1\),这个过程是可能一直重复的,直到某一次进位以后,我们宣布低位不在给最高位贡献进位,此时终于递归进了一个子问题。
然后发现根据这个过程的分析其实已经直接把状态和转移设计出来了。状态:\(f(i,S,0/1,0/1)\),表示只考虑最低的 \(i\) 位,要求所有使用的 \(n\) 个 xor 操作的奇偶性为 \(S\)。第一个 \(0/1\) 表示起始状态是 \(s\) 还是全 \(0\)。第二个状态表示目标状态是 \(t\)(不允许向第 \(i+1\) 位进位),或者是全 \(0\)(最后一步一定是向 \(i+1\) 位进位,且之前的步骤里也不能进位)。
转移其实我们已经从最高位的视角描述过了。注意产生进位的转移里,可以把这个一直重复的过程看作是在 \(2^n\) 个点的图上的一条路径,所以要用最短路算法去更新。暴力去做就能做到 \(O(4^n\log)\) 的复杂度。其中 \(\log=40\)。
CF1007E Mini Metro
这个题的思想和上面一个题是有相似之处的,但是转移细节繁琐了很多。
首先有个很重要的起手是在结尾添加一个增长量和容量足够大的车站保证每次都恰好移走了 \(k\) 个人。
入手点是,如果我们移动走了第 \(i\) 站的一些人,那么在这之前一定会把第 \(1\sim i-1\) 站的人已经清空。
同样的角度,我们从最后一个站的视角来看:要么说没有任何一次清空操作涉及他,那首先它自己自生自灭得是合法的,然后变成一个子问题。要么我们枚举最后一次设计他的清空操作在时刻 \(r\)(注意不一定清除完了),那么首先考虑时刻 \(r\) 结束后,前面 \(n-1\) 个站台都是空的,第 \(n\) 个站台可能依旧有一些人,在后续的 \(t-r\) 天里前 \(n-1\) 天又划归成了一个子问题,但是说初始每个站台都没有人(而不是 \(a_i\) 个人)。那么也容易加一个 \(0/1\) 来区分不同的子问题。虽然第 \(n\) 个站台有一些人,但是因为我们知道每次清空操作恰好删去 \(k\) 个人,所以使用的操作数就是个区间 \([L,R]\),且确定操作数就确定了第 \(n\) 个站台在时刻 \(r\) 结束后还剩多少人。
因此,设 \(f(i,j)\) 是前 \(i\) 个站台,想要在 \(j\) 天内合法,最少需要清空几次。注意我们要求每次都拿走 \(k\) 个,不然就算有方案也认为不合法(也就是 \(=\infty\) 的情况)。为了处理上面的情况 \(2\),我们再设 \(g(i,j)\) 是在保证合法的基础上,第 \(j\) 天结束时清空了 \(1\sim j-1\) 这些站台,所需要的最少次数。转移类比上面去做就行了。复杂度 \(O(nt^2)\)。
IOI2018 seats
这个题很有启发性啊。先考虑一维,发现一维我都不会啊?
一维的话相当于是连通块个数为 \(1\),这种东西考虑用一些特征来描述。发现点减边容斥是可行的,在值域上维护即可。
二维的话我们不光要求连通块个数还得保证是个矩形,如果不是矩形的话你这个连通块一定有那种凹角/凸角,就是说存在一个连通块外的格子,边缘和 \(\ge 2\) 个连通块内的格子相邻。维护之即可。
总结还是能运用明白点减边容斥不?
JOI2016 Final 领地
这题挺高妙的感觉。
看着很像什么平面图欧拉定理但是仔细想想就发现不对劲。
令一轮走完后走到了 \((x,y)\),假设向量 \(v(x,y)=0\) 那就直接暴力判断即可。否则我们第一轮的 \(n\) 个点相当于引出了 \(n\) 条射线,这射线上依次有 \(k\) 个点是存在的。
正方形也同理,如果一个正方形在时刻 \(t\) 存在,时刻 \(t+1\),把他按照向量 \(v\) 去平移得到的正方形也一定存在。
那么一个正方形,考虑四个点出现的最早时刻如果不是 \(1\) 就可以把他往 \(v\) 的反向平移,然后我们只关注至少有一个点是在第一轮确定的正方形,由他们向 \(v\) 方向引射线,然后同样有若干个正方形是能走到的。
我们只用支持快速求一个点最早何时存在即可。容易用 STL 的一些内容去维护。