2024.11
2024.11
AGC006C
先想想跳了一次会发生什么。
先设兔子 \(i\) 跳了一次的期望位置是 \(f(i)\) 。那么 \(f(i)\) 满足 \(f(i)=\frac{1}{2}(2f(i-1)-f(i))+\frac{1}{2}(f(i+1)-f(i))=f(i+1)+f(i-1)-f(i)\) 。
这个东西很好看,差分一下,设 \(d(i)=f(i)-f(i-1)\) 。看看执行一次操作 \(i\) 会发生什么。
相当于交换 \(d(i)\) 和 \(d(j)\) 。然后倍增就好了。
CF331D3
只查不修想到倍增,想想如何去维护这个东西。我们同时要维护 \(f(x,k)\) 表示走了 \(2^k\) 条线段后到了哪条线段。还要维护 \(g(x,k)\) 表示走了 \(2^k\) 步后距离是多少。
现在我们只需知道每条线段最后走到了哪条线段, 就是 \(f(x,0)\) 和 \(g(x,0)\) 。我们可以将线段的四个端点排序,线性扫描一遍。用 std::multimap 更新答案。
最后我们只需最后处理一下线段最后在线段上的位置即可。
P4694
容易想到费用流,连三种边, \(s\to i\) 流量为 1 费用为 \(a(i)\) ,表示给工厂 A 加工; \(i\to t\) 流量为 1 费用为 \(b(i)\) ,表示给工厂 B 加工;每个 \(i\le j\) 连边,流量为 1 费用为 0,表示工厂 A 加工完给工厂 B 加工,需要限制。
这个加边是 \(O(n^2)\) 的,就算使用线段树优化建图也无法满足 \(n=500000\) 的限制。
我们想想这个东西有什么性质。众所周知,费用流的费用函数 \(f(t)\) 是关于流量的凸函数,所以我们可以考虑用 wqs 二分,二分出流量为 \(k\) 时的答案。
首先这个东西是个下凸函数,我们给边权减去一个 \(k\) 算贡献,然后统计答案。现在,我们要考虑如何快速计算这个网络的最小费用最大流,直接做肯定不行,我们考虑模拟费用流:
考虑一个贪心策略。对于每个 \(j\) 我们先把所有 \(i\le j\) 的 \(a(i)\) 放到一个小根堆里面,然后我们每次找到一个最小的和它匹配。
但是这个东西可以被随便卡掉,我们考虑模拟费用流当中的“退流“操作,我们加入一个负的边权进小根堆里面,表示和 \(j\) 断开匹配并与 \(j'\) 匹配。
这样就做完了(这个东西貌似也叫返回贪心)。
P5405
首先这个东西构成一棵树,但既不是内向树也不是外向树。我们先假设一号点为根。考虑一个子树的贡献。
我们发现子树中的点如果在 \(x\) 的后面出现很好维护,先假设所有边都是外向边。点 \(x\) 比子树中所有的点先出现的概率为:
其中 \(s(x)=\sum_{y\in subtree(x)}w(x)\) , \(sum=\sum_{i=1}^n w(i)\) ,这个式子的意思是在这个子树以外的点都有可能在 \(x\) 的前面出现,所以枚举这个 \(x\) 在第几次出现,然后加起来。
化一下式子发现这个东西就是 \(\frac{w(x)}{s(x)}\) 。
所以我们设计状态 \(f(x,k)\) 表示处理完子树 \(x\) ,\(w(x)\) 之和为 \(k\) 的概率。
然后我们考虑内向边的贡献,这想到于强制要求 \(y\) 在 \(x\) 前面出现。如果只有一条边,我们直接把它反过来算,让它在 \(x\) 后面出现,最后容斥回在前面出现。
这个贡献是 假设它不存在的贡献 - 把边反向的贡献。
P3321
设 \(f(i,j)\) 为选了 \(i\) 个数在模 \(m\) 的意义下乘积为 \(j\) 的个数。
由于 \(n\) 很大,我们想想如何用优化计算的过程,让他变成 \(O(\log n)\) 。矩阵存 \(M\) 存不下,我们想想如何用 快速幂 做这个东西。
我们把 \(f(x,*)\) 看成一个多项式。答案为 \(f(n)\) 的第 \(x\) 项。
现在我们想想如何合并两个多项式 \(f,g\) ,合并的过程是:
套路算原根转为加乘卷积就做完了。注意我们只能维护一个多项式的 0 到 \(m-1\) 项,所以我们每次做完 NTT 后把 \(\%m\) 的同余系加起来就好了。
算原根的话先把 \(m-1\) 质因数分解,然后枚举 2 到 \(m-1\) ,第一个满足 \(i^{\frac{m-1}{p}}\not\equiv 1 \pmod m\) 的就是原根。
qoj 6351
先想想怎么对一个 01 串统计有多少个本质不同的非空子序列。我们可以用 dp 解决这个问题。
我们设 \(f(i,0/1)\) 表示 1 到 \(i\) 的前缀中有多少个本质不同的非空子序列结尾为 \(0/1\)。
如果当前第 \(i\) 个位置为 0 那么所有前缀 \(i-1\) 子序列都可以再后面加上一个 0 成为新的子序列。 \(f(i,1)\) 从上一个位置转移。
我们想想这样会不会算重。如果一个子序列有一个子序列的子序列结尾和它相同。那么它一定也在这个前缀的子序列中,所以不会算重。
这样写来,如果当前位置为 0:
我们开 \(O(n)\) 空间太傻了。直接记 \(x=f(i,0),y=f(i,1)\) 。变为 \(x'=x+y+1,y'=y\) 。一个神奇的转化是 令新的 \(x,y\) 为原来的 \(x+1,y+1\) 。于是式子变为 \(x'=x+y,y'=y\) 。
然后我们想到辗转相除法。每一个 \(x,y\) 都是从 \(x=1,y=0\) 或 \(x=0,y=1\) 一步一步加回来的。
所以有 \(\gcd(x,y)=1\) 。这是两个变量非常不好,所以变为 \(\gcd(x,n+2)=1\) 。
我们还要想想第 \(k\) 大怎么算。如果 \(x'=x+y\) 则我们加了一些个 0,否则我们加了一些 1。
字典序从前往后考虑,\(x,y\) 慢慢增加。所以我们把 dp 反过来考虑这个问题。
如果 \(x\ge y\) 那么当前填 0,字典序更小,否则填 1。对应到 exgcd 当中就是比较 \(\frac x y\) 。
如果两个相等,就继续比较下一个。我们发现,如果 \(x\) 越小,那么 \(y\) 越大,所以一开始 \(\frac x y\) 越小。所以我们要找的就是第 \(k\) 小满足 \(\gcd(x,n+2)=1\) 的 \(x\) 。用二分解决这个问题。
二分 mid ,我们就是要找 \(\sum_{i=1}^{mid} [\gcd(i,n+2)=1]\) 和 \(k\) 比大小。
莫反推一下式子,发现答案为 $\sum_{d|n} \mu(d)\left \lfloor \frac{mid}{d} \right \rfloor $ 。预处理一下只加 \(\mu(d)\ne 0\) 的更快。
P5363
这个东西是阶梯 Nim 。把每个金币前面的空位看作这个位置的石子。每次移动金币相当于把把一些石子移动到下一个位置。最后一个位置相当于把它扔掉。
我们发现只有从后往前奇数位置的石子是有用的。每个偶数数位置上的石子经过 A 和 B 同时操作又回到了偶数位置。一直这样操作最后把它们扔到 0。
所以我们只用考虑 $\left\lfloor \frac{m+1}{2} \right\rfloor $ 个位置就好了。如果它们异或和为 0 那么先手必败,然后反过来计数。
我们设 \(f(i,j)\) 表示考虑前 \(i\) 位,剩下 \(j\) 个位置的方案数,答案把偶数位置的金币插板就是 \(\sum f(0,j)\times\binom{j+m/2}{m/2}\) 。
转移考虑有偶数个位置第 \(i\) 位为 1 。转移即为:
P2490
同时取 \(K\) 堆石子,相当于同时操作 \(K\) 次 xor 操作。我们把所有第 \(i\) 个二进制求和,然后变为经典取木棍。如果 \(\% (K+1)=0\) 则后手必胜,如果有一个 \(\%(K+1) \ne 0\) 则先手必胜。
所以我们反过来 dp 。设 \(f(i,j)\) 表示前 \(i\) 位剩下 \(j\) 个位置。转移和上面几乎一模一样。除了 \(k\) 的条件为 \(k\% (K+1)=0\) 。
P5644
算第一个人在别人后面死太困难了,但是让他第一个死很简单。
我们可以让他在某个集合 \(S\) 的人前面死。 \(P(S)\) 为 \(\frac{w(1)}{w(1)+\sum_{i\in S}w(i)}\) 。
答案容斥一下解决,容斥系数为 \((-1)^{|S|}\) 。
这个东西没办法直接做。我们 把式子化为:
然后我们一次性求出 \((-1)^{|S|} \sum_{i\in S}=K\) 的个数,设个数为 \(f(i)\) ,答案变为:
这个东西直接生成函数,我们直接设 \(O(n)\) 个多项式 \(1-x^{w(i)}\) 。暴力乘起来就好了。
ARC187B
算联通块太麻烦了,不如算 \(i\in[1,n]\) 中 \(i\) 与 \(i+1\) 不连通的方案数。
我们看看怎样的两个点是不联通的。如果两个点 \(i\) 和 \(i+1\) 不连通,那么一定有 \(MinPre(i) > Maxsuf(i+1)\) 。其中 \(MinPre(i)\) 为前缀最小值, \(Maxsuf(i)\) 为后缀最大值。
证明是容易的,我们用 dp 分别计算前后缀的方案数即可。
CF843D
先跑一遍最短路,我们只用考虑最短路如何改变。
我们考虑 dijkstra 的过程:每次选取一个 \(d(x)\) 最小的、没被访问过的答案更新所有边。
这个过程对于每条边 \(x \to y\) 一定只会执行一次。
如果一条 \(x\to y\) 边改变。我们在 \(x\) 前执行的 dijkstra 都是不变的。我们只用考虑后面的变化。
由于这道题每次边权只会增加 1 ,所以最后答案的变化是 \(\min(c, n-1)\) 的。设所有答案的增量为 \(V\) ,我们的时间复杂度和它挂钩。
每次直接遍历不太好,我们不妨只考虑每条边的 增量 对答案的贡献。一条边 \(x\to y\) 的增量可以记为 \(d(x) - d(y) + e(x\to y)\) 。
我们一开始跑完最短路时满足 \(d(y) \ge d(x) + e(x\to y)\) 。现在我们对增量跑最短路,设 \(f(x)\) 为每个 \(d(x)\) 的增量。显然它也满足 \(d(y)+f(y) \ge d(x)+f(x) + e'(x\to y)\) 。
所以等价于 \(f(y)\ge f(x)+ (d(x) - d(y)+e(x\to y))\) ,这里的 \(e(x \to y)\) 是改变后的边权。
我们每次跑最短路即可。其实这题边权为 1 ,我们可以对值域开 \(O(V)\) 个 queue 。每次取最小的点转移即可。这种做法细节较多,每次要保证取出的 \(f(x) \ge k\) ,否则它已经被别的点更新过了。还要保证每次的 \(f(x) \le \min(c, n-1)\) ,否则我们更新到了一堆 \(+\inf\) 。
P10789
题面好长好长。想想不算很难。我们发现这个登山的路径就是在不断的向上爬和向下跌。
先简化一下贡献。冲刺到点 \(p\) 时要求 \(L(x)\le dep(x)-dep(p)\le R(x)\) ,移项等价于满足 \(dep(p) - R(x)\le dep(p) \le dep(p) - L(x)\) 。我们直接让 \(L(x)=dep(x) - R(x),R(x)=dep(x)-L(x)\) 。
第二个条件是对于冲刺的序列 \(dep(j)<dep(i) - h(i)\) 其中 \(i<j\) ,相当于 \(dep(j)\le dep(i)-h(i)-1\) 。我们直接让 \(h(i)=dep(i)-h(i)-1\) ,相当于 \(dep(j) \le h(i)\) 。
每次从 \(x\) 冲刺都相当于找到一个 \(y\in subtree(x)\) ,跌到 \(y\) 在冲刺到祖先 \(p\) 。要满足两个条件 \(L(x) \le dep(p) \le R(x)\) 且 \(dep(p) \ge min_{t\in p(x\to y)} h(t)\) 。
不妨设 \(f(x)\) 为冲刺上来的路径个数。我们考虑有多少个点能贡献这个 \(x\) ,每次暴力枚举转移可以做到 \(O(n^3)\) ,前缀和优化可以做到 \(O(n^2)\) 。
这一堆不等式想到倍增 + 差分优化这个东西,算出有多少个东西能更新。
我们先看限制 2 。对于一个固定端点的 \(x\) 和 \(y\) 能贡献的 \(p\) 是一段区间。再看限制 1 。每次固定 \(y\) 能贡献的 \(p\) 也是一段区间。
不妨我们先固定一个 \(y\) 判断出可以到达的 \(p\) 和可以跌下来的 \(x\) 。用差分算出 \(x\) 的个数。
但是这样会算重。我们只用加 \(x\to y\) 中 \(h(x)\) 最大的贡献就好了。
然后维护再 dfs 一遍,每次在树状数组上查答案就好了。
P4425
题面意思等价于在某个时刻都可以往前走一步或留在原地。第 \(i\) 个点都会在 \(T(i)\) 时消失。求最小的时间将每一个点都访问一次。
每次肯定往前走,停下来肯定不优。所以枚举一个位置 \(i\in [n,2n)\) 当作起点。对于所有的点 \(j\in(i-n,i]\) 都满足 \(t-(i-j)\ge T(j)\) 。所以可以化为 \(t_{min}=\max\{T(j)-j\}+i\) 。
相当于 \(t=\min_{n\le i<2n}\{\max_{i-n< j\le i}\{ t(j)\}+i\}\) 。把下标映射一下,变为 1 到 \(n\) 。
所以等于 \(t=\min_{i\in [1,n]}\{\max_{i\le j\le 2n}\{t(j)\}+i\}+n-1\)
对于一个 \(i\) 算出后缀最大值就是答案。我们再考虑一个怎样的 \(j\) 可以贡献答案。相当于找到一个 \(i\) 满足 \(a(i)>a(j)\) ,答案就是 \(a(j)+i+1\)。
所以我们维护一个单调栈,栈里的元素分别为 \(p(0),p(1),p(2),\cdots,p(m)\) 且 \(p(0)=0\) 。
答案相当于 \(\min_{1\le i\le j}\{a(p(i))+p(i-1)\}+n\) 。使用兔队线段树合并两个儿子的信息。
qoj 9135
容易发现,如果选择一个位置 \(x\) 使用传送阵,并且已经把宝藏锁定在区间 \([l,r]\) 中。那么下一个宝藏会出现的位置是 \([2x-r,2x-l]\) 。
我们容易设出 dp 式子,但是这个 dp 转移不一定会使区间缩小。我们发现如果 \(l<1\) 或 \(r>n\) 时这个区间才缩小,否则区间长度不变。
通常我们转移时都是以区间长度为基准转移,从区间长度小的转移到区间长度大的状态。
我们可以先把区间变小的转移先做了。然后我们发现了区间长度相同的状态构成一个稠密图。我们使用 \(O(n^2)\) 的 \(dijsktra\) 求出这些状态的最短路即可。

浙公网安备 33010602011771号