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)=f(i)-f(i-1)=(f(i+1)+f(i-1)-f(i))-f(i-1)=f(i+1)-f(i) \]

\[d(i+1)=f(i+1)-f(i)=f(i+1)-(f(i+1)+f(i-1)-f(i))=f(i)-f(i-1) \]

相当于交换 \(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\) 比子树中所有的点先出现的概率为:

\[\frac{w(x)}{sum} \sum_{i=0}^n\left( \frac{sum-s(x)}{sum} \right)^i \]

其中 \(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\) ,合并的过程是:

\[h(i)=\sum_{j\times k=i} f(j)\times g(k) \]

套路算原根转为加乘卷积就做完了。注意我们只能维护一个多项式的 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:

\[f(i,0)=f(i-1,0)+f(i-1,1)+1 \]

\[f(i,1)=f(i-1,1) \]

我们开 \(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 。转移即为:

\[f(i,j)=\sum_{k\%2=0} f(i+1,j+k\times 2^i) \times \binom{\left\lfloor \frac{m+1}{2} \right\rfloor}{k} \]

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|}\)

\[ans=\sum_{S\subseteq [2,n]} (-1)^{|S|} \times P(S) \]

\[ans=\sum_{S\subseteq [2,n]} (-1)^{|S|} \times \frac{w(1)}{w(1)+\sum_{i\in S}w(i)} \]

这个东西没办法直接做。我们    把式子化为:

\[ans=\sum_{S\subseteq [2,n]} \frac{w(1)}{w(1)+(-1)^{|S|} \sum_{i\in S}w(i)} \]

然后我们一次性求出 \((-1)^{|S|} \sum_{i\in S}=K\) 的个数,设个数为 \(f(i)\) ,答案变为:

\[ans=f(i) \times \frac{w(1)}{w(1)+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\) 求出这些状态的最短路即可。

posted @ 2024-11-04 10:43  lichenyu_ac  阅读(18)  评论(0)    收藏  举报