2025.8.26 往后的记录

只记录思考和做法,写的时候一般比较累所以大概率不会用 latex。

P5979 [PA 2014] Druzyny

题意是给定每个接受的范围 [l_i,r_i] 求最多能分多少段使得段内的所有人都接受它所在段的长度,并给出满足个数最多的方案数。

n<=1e6

考虑做一个 dp,令 f[i],g[i] 表示前 i 个段的最大划分的长度,方案数。转移就枚举前面的 j 满足 j 到 i 满足条件然后转移。这里可以把 f,g 封装成一个类型,然后定义合并为取长度最大的那个保留如果长度相同就保留长度方案数相加。

优化就考虑做 cdq 分治,每次端开中间,考虑左边的数作为上述转移中的 j 转移向右边的上述转移中的 i。那么我们记录lmx,lmn,rmx,rmn分别为左边的后缀l的mx,r的mn以及右边的前缀l的mx,r的mn。那么有 max(lmx_j,rmx_i)<=i-j<=min(lmn_j,rmn_i)(这里其实枚举的是左端点-1),拆掉变成:lmx_j<=i-j<=lmn_j且rmx_i<=i-j<=rmn_i。对于第一个,其实是在确定了j的情况下筛选出来了可以转移过去的 i(一个区间),但是它能转移的 i 不一定能满足第二个条件,这个很难直接处理。所以我们做一个扫描线,每次对于一个i把当前时刻的所有事情处理完之后,就对于第二个条件解出所有的i(也是一个区间)。所以我们可以维护一棵线段树,我们把在此时 j 能转移向 i 的所有位置 j 变成它对应的转移值,然后还为了满足第二个条件,就在线段树上查一下那个区间的信息收集上来的结果即可。

uoj37 主旋律

题意是给你一个有向图,求删边方案数使得强连通分量个数=1。

考虑令 f[S] 表示集合 S 内部的图(点+内部边)强连通的方案数,考虑正难则反,转化为统计不强连通的方案数。不强连通等价于缩点(缩成若干个极大 scc)后是个 DAG,且点数 >1。于是根据经典套路我们枚举所有入度为 0 的极大 scc 中的点组成的集合,令它为 T。那么我们记 g[T] 表示 T 内点(就只考虑内部的边)划分为若干入度为 0 的 scc 的方案数。我们可以得到 \(f[S]=sum(g[T]*(-1)^{|P|+1}*2^{edge(T,S-T)+edge(S-T,S-T)})\)\((-1)^{|P|+1}\) 是容斥系数,其中 \(P\) 为 T 中的 scc 个数,这个不能直接定量,所以我们可以把 g[T] 定义为奇数个 scc 的方案数-偶数个 scc 的方案数\(edge(T,S-T)+edge(S-T,S-T)\):T->S-T 中的边不影响 DAG,S-T->S-T 的边因为 T 中已经有个 scc,那么剩下就算只缩成一个,那么点数还是>1,因此S-T内部的边随便连,S-T->T的边是全都要砍掉的,因为入度为 0。所以现在就是要求 g[T],考虑转移。如果单独一个 scc,就是 dp[S],否则考虑枚举 lowbit(T) 所在的 scc,那么得到 g[T]=dp[T]-sum(g[S-T']*dp[T']),T' 为 lowbit(T) 所在连通块。这样就做完了。当然有一个细节就是在 f[S] 的转移的时候,T=S 的时候你不能把 dp[T(S)] 也减掉,因为这个时候你不能把整个划分成一个 scc,这个是合法的。

P5655 基础数论函数练习题

题意是给一个数组,对于所有区间的 lcm mod 998244353,n<=5000.

记录 \(b_i=\frac{a_i}{gcd(a_i,lcm(a_{i+1},a_{i+2},...,a_n))}\),那么答案就是 \(\prod b_i\)。观察 \(b_i\) 的式子发现 \(lcm(a_{i+1},a_{i+2},...a_n)\) 就是 \(\prod_{j=i+1}^n b_j\),于是 \(b_i=\frac{a_i}{gcd(a_i,\prod_{j=i+1}^n b_j)}=\frac{a_i}{gcd(a_i,\prod_{j=i+1}^n b_j \ mod\ a_i)}\)。于是你就可以对 \(\prod_{j=i+1}^n b_j \ mod\ a_i\) 这个东西直接扫一遍算,于是这样就做完了。

接着考虑怎么对一个数组的所有区间求。我们考虑从前往后不断插入数,然后维护 \(b\) 的修改,那么对于插入了前 \(j\) 个数时,此时就有 \(w_{i,j}=\prod_{k=i}^j b_k\),这里的 \(b\) 是在插入了前 \(j\) 个数时的 \(b\)。现在就是要维护这个 \(b\)。你直接按照上面的方法一个一个改是不行的。这个时候是 n^3log的复杂度(log是用来求gcd的)。

我们考虑修改是怎样的,设 \(b'_i\) 为新的 \(b_i\),有 \(b'_i=\frac{b_i}{gcd(b_i,\prod_{k=i+1}^j b'_k)}\)(你把每个质因数指数在这里写一下就知道了(gcd->min,lcm->max))。

\(b_i,b'_i\) 做比(显然有 \(b'_i|b_i\))得到:\(c_i=\frac{b_i}{b'_i}=gcd(b_i,\frac{a_i}{\prod_{k=i+1}^j c_k})\)。所以你对 \(c_i\) 递推一遍然后把 \(b_i\) 除掉 \(c_i\) 即可。

P4065 [JXOI2017] 颜色

题意是给定一个数组 a,要求选择一些数值,然后在 a 中把数值在选择之中的数标记,求标记的数是一个区间的方案数。考虑反过来 check 一个区间合不合法,其实就是要求在区间里面出现的数值所在原数组中对应的位置全都在这个区间里。我们考虑给每个数赋权,其它的数随机赋权,对于每种数值最后的位置的那个数赋成前面同数值的数的 xor。那么相当于对于区间内的所有数 xor=0,直接统计即可。

ARC132E Paw

*3100 我的评价是不如 *1900

题意是给你一个包含 .<> 的字符串,每次你可以等概率选择一个 . ,把他填成 ?,然后等概率选 左右 中的一个方向,然后一直往那边覆盖和你行进方向相同的 <>,直到遇到一个 .。求最后不能选的时候 < 的期望。|string|<=100000

我们考虑最后的字符串形态,一定是 <<<<<<====>>>>>>>,= 表示不变,<> 表示痕迹,=两边(left-1,right+1)是两个 .。我们考虑枚举这相邻的两个 .。那么此时的 < 数量是确定的,所以我们统计概率。此时因为中间是隔开的,所以两边一定是分别往边界的方向覆盖,是独立的,这很好。我们记 f[i] 表示 i 个 . 来覆盖不往反方向覆盖(不能影响)并且把自己的方向覆盖完的概率。我们有 \(f[i]=f[i-1] \times \frac{2i-1}{2i}\),这个是显然的,你考虑只有一次性覆盖完的是不行的,否则相当于一个盖了一个,规约到 n-1 的子问题。那么在这个间隔的概率就是 \(f[l]*f[r]\)

CF303E Random ranking

*3000,但是我喜欢你。
题意是有 n 个人,第 i 个人的分数在 [L_i,R_i] 随机(可能为实数),对于每个 (i,j) 求第 i 个人的分为第 j 小的概率。n<=80。

首先把所有 \(L_i,R_i\) 当成断点将值域分段,那么对于第 \(i\) 个人要考虑排名也就是看其它人的分在它前面有多少。枚举第 \(i\) 个人在第几段,那么其它人在前面的段肯定就 \(<a_i\),如果和 \(i\) 在同一段,那么因为大家都是随机撒点,所以可以认为就是 \(i\) 在这一段内的 rk 随机,这个概率和在这一段内的人数有关。所以就 dp 一下子,记录一下和 rk 相关的信息:在前面的段的人数,当前段的人数 即可。这样是 \(O(n^5)\) 的。考虑对这个 缺一 刻画,可以用缺一分治,做到 \(O(n^4 log)\)

P6189/P10613 跑步

题意就是把 n 划分成本质不同的凑数方案(方案里每个数都是正整数)。n<=10^5

我们考虑根号分治,定一个 B=sqrt(n)。对于<B的数,我们直接把每个数当成一个物品做完全背包,这样就处理了<B的方案数,令这部分的f[i]表示<B的数组成i的方案数。对于>=B的数,我们考虑枚举有多少个>B的数,这个数量也是根号级别的。我们对于这部分怎么统计呢,考虑经典 trick,每次选择:扩充序列,给所有数+1(当然你这样统计出来的是每个数>=1的限制的序列方案数,我们最后给每个数+B即可)。这个东西用 f[i][j] 表示当前序列长度为i且和为j的方案数,转移显然。最后我们枚举>B的个数c以及>B部分的和即可。

ARC098F Donation

题意是给定一张无向连通图,每个点有约束ai,bi表示经过这个点需要至少有ai的钱,同时你也可以选择用bi投资i,你可以通过边移动。求最开始有多少钱才能把所有点都投资。n<=10^5

我们考虑倒序走的过程,那么就相当于你经过一个点需要至少有 ci=max(ai-bi,0) 的钱,然后你可以在这里抢钱(钱数加bi),然后要把所有点都抢一遍,这样的话初始的钱数就是最后抢完了以后手里的钱。因为我们的钱是不会减少的,所以肯定可以在走过一个点以后再随便走。因此可以发现先走小的一定是优秀的。那么假设定了起点以后我们每次就相当于选一个能走到的里面 ci 最小的,然后加上 bi 每次这样拓展。这样类似 prim 是 n^2 的。我们发现这个和最小生成树的过程比较类似,考虑建出来重构树,一条 (u,v) 的边权为 max(c_u,c_v)。那么建完了以后 c 大的在上面。我们考虑 dp 规约子问题。为什么可以?因为假设现在对于一个点,它有若干个儿子的子树,因为下面 c 小,上面 c 大,因此肯定是先做子树再往上走,我们要决策只是子树间的事情,所以可以 dp。接下来考虑怎么 dp。令 f[x] 表示从 x 子树走完所需要的最小初始钱数(是转化后的最初),s[x] 表示 x 的子树内的 b 之和,那么最后答案就是 f[rt]+s[rt](注意这里的最终钱数才是原题里的初始钱数,所以是这个式子)。s[rt] 可以直接预处理。f[x] 的话我们考虑一定是从一个点走到 x 然后在把子树内的点跑一遍,的(证明很简单,因为你考虑走到x的时候你走了哪些点,如果你经过的点里有两个不同子树的,意味着你已经经过了x,矛盾或者说你可以把多余的一段删掉),既然这样我们考虑那个点是从哪个子树走上来的,假设是 v 的子树内一个点走上来了,那么你考虑他是先走到 v 再往上一步到 x,也就是有能走到 v 和走到 v 以后还有钱走到 u 这两个限制。那么就是 f[v] 和 c[x]-s[v] 的最大值转移到 f[x]。这样就做完了。

P7323 [WC2021] 括号路径

题意是给定一个无向图,边上有k个类型的括号,图上有一些成对的边,每一对形如:u->v有一个类型为w的左括号,v->u有一个类型为w的右括号,求有多少对 (u,v),u<v 满足存在一条u->v的路径使得路径上边按顺序拼接后得到的括号序列是合法的。n<=3*10^5。

有两个性质,就是我们记 h[i][j] 表示 i,j 的合法性。那么有传递性:h[i][k]=1且h[k][j]=1可以推出h[i][j]=1。对称性:h[i][j]=h[j][i]。这样的话我们思考这样一个东西:把h[i][j]=1的(i,j)连边,那么连通快内相互可达。观察一下这个图的性质,显然路径长比较长的有边的 (i,j) 是由小的边拼起来的。因此我们只用考虑长度=2也就是最短的合法路径即可。合并用启发式即可,同时因为可能存在合并后由新的东西需要合并的情况,考虑维护一个代处理的合并信息的队列,每次取队头处理即可。

P3813 [FJOI2017] 矩阵填数

题意是给定一个 n*m 的矩阵,有 k 个限制形如一个子矩形的max=v。已知所有数都在1,2,3,...,t。求方案数。

简单题。容斥过后限制等价于<v,于是离散化以后乘法原理即可。

CF1120D Power Tree

题意是给定一棵树,求选择一些点控制,每个点控制有对应的代价,控制的点可以对子树内整体任意加减任意数,求使得可以让所有叶子的值任意取的最小花费。

考虑先把问题拍到 dfn 序上,那么一个子树对应一个区间。考虑做差分,那么此时就是两个端点可以任意调整,显然连通的时候可以整体的任意调整,最小生成树跑一遍即可。

P5524 [Ynoi2012] NOIP2015 充满了希望

题意懒得说了,写得很清楚。

考虑反过把每一个操作 3 向答案里面贡献。那么我们注意到一件事情,假设一个操作包含了这个 3 操作并且这个操作询问的位置上有值,这个值显然是确定的,就是在这个时刻它的值,我们设使这个位置的值最后一次改变的操作id=t,那么l<=t且i<=r的(l,r)就ans加上这个确定的值,于是二维偏序即可。

qoj5402 术数树 & P4151 [WC2011] 最大XOR和路径

1.包含一个点的简单环张成了包含一个点的所有环
2.考虑图的任意一棵生成树,取两点树上路径权值和异或上任意环的异或值构成了这两点间的所有路径
3.任取一条路径,任意异或一个环,可以生成所有路径

这种题的优美结论,因此我们发现走到一个环,可以分为:走到环上一个点,走完这个环两步。走到环的那个路径走两次相当于没走,可以认为是可以瞬移到一个环上去,因此用线性基维护每个环即可。

AT_jsc2019_final_h Distinct Integers & 单侧递归线段树维护前缀最大值

题意是给定一个序列 \(A\),有 \(q\) 个操作,每个操作是单点修改或者给定 \(L,R\) 查询有多少个 \([L,R]\) 的子区间且满足内部数不重复的数量。\(n \leq 5 \times 10^5\)

\(p_i\) 表示 \(A_j=A_i(j<i)\)\(max(j)\)(即上一个和 \(A_i\) 相等的位置)。那么考虑枚举 \(L \leq r \leq R\) 即子区间的右端点,那么有 \(l>max_{i=1}^r p_i\),于是对于 \(r=j\) 的时候子区间个数是 \(j-max(max_{i=1}^j p_i,L-1)\)。sigma 可以拆成前后两部分,后面的 max 拆开可以首先线段树二分,一部分 max=L-1,一部分是 \(max_{i=1}^j p_i\)。于是现在比较难做的就是一个区间的前缀最大值,这个直接使用单侧递归线段树即可。

这里记录一下单侧递归线段树的流程,参考 兔队 sgt

这里只记一下楼房重建的做法。

我们考虑维护线段树上每个节点对应的区间 max,对于单点的修改我们很好做,关键是要维护信息的合并或者说怎么计算答案,这里也就是要研究怎么 pushup。我们考虑定义 calc 函数:

def calc(rt,pre){
    if(rt is leaf)return max[rt]>pre;
    else{
        if(max[left_son]>pre)return calc(left_son,pre)+ans[rt]-ans[right_son]
        else return 0+calc(right_son,pre)
    }
}

calc(rt,pre) 表示对于 rt 内部的区间,在这个区间前面插入 pre 这个数的情况下的答案。

我们可以定义 cnt[rt] 代替max[left_son]>pre时ans[rt]-ans[right_son]也就是rt只考虑rt整个树的话右子树的答案。对于calc里面只需要简单做一个替换即可。然而这意味着我们要同时维护cnt。这个其实是好做的,我们只需要对于 cnt[rt]=calc(right_son,max[left_son]) 即可。

k-d tree

这里只记一下 2-d tree。考虑按照 x,y 交替划分,每次对于 x 或 y 的中位点划分,切成上下/左右两个矩形,当成儿子。建树就是这样,显然一个子树是一个矩形,查询就直接跟普通线段树差不多的拆一下即可。插入的话我们考虑每次找到相应的位置,直接插进去然后 pushup 上去即可。但是单单这样做有问题,因为你得保持建树的时候的优秀结构才能保证复杂度。考虑如果 \(0.75 \times sz(x) \leq max(sz(ls),sz(rs))\) 那么就对整个树重新建一遍。

查询和插入据说是 O(sqrt) 的,不太清楚的样子。

uoj887 & gym104536H

发现两个可爱小清新最优化题!

uoj887
考虑对于一个位置,它能取到的下界是后面的数的 min。于是考虑从后往前扫,维护一个小根堆,每次取出最小值,这个是答案的下界。构造是简单的。

gym104536H
首先答案的上界是 \(\frac{n(n=1)}{2}\),然后考虑哪些东西可以扣掉,令前缀最大值为 \(b_i\),那么可以扣掉的就是 \(b_i=a_i=i\) 的数。于是就做完了,我感觉挺难想的。。。

AT_abc262_h & P4229 某位歌姬的故事

考虑对于一个限制:区间 \(max=v\),等价于这个区间内所有数 \(\leq v\) 且存在一个数 \(=v\)

先把第一个条件都处理了,对于每个数 \(i\) 求出它的上界 \(w_i\)。此时对于每个 \(a_i \leq w_i\) 就能满足第一个条件了。接着考虑处理第二个条件。然后我们注意到一件事情,对于所有 \(w_i=v\)\(i\),它们是可以直接干涉所有 \(l_i,r_i,p_i\)\(p_i=v\) 的限制的。然后我们再考虑 \(w_i<v\) 的位置是否可以干涉,我们把所有 \(p_i=v\) 的限制拿出来,对于其中一个 \([l_i,r_i]\),如果 \([l_i,r_i]\) 中有 \(w_i \ne p_i\),那么显然是有另一个 \(p\) 更小的覆盖了它,那么显然它就帮不上忙了。对于 \(w_i>v\) 的,那么此时显然这些位置没有被 \(p=v\) 的限制包含,显然也是帮不上忙的。所以只有 \(w_i=v\) 的位置的取值可以干涉到一类 \(p=v\) 的限制的成立情况。

因此我们可以发现 \(w_i\) 不同的位置之间相互独立,于是我们考虑对于每一种 \(w_i\) 单独 \(dp\) 出来方案数,最后乘起来就是对的了。对于其中一种 \(w_i=v\),显然干涉到 \(p=v\) 的限制的只是每个数是 \(<v\) 还是 \(=v\)(因为每个限制相当于是要求区间内有一个 \(=v\) 的)。我们考虑记录 \(f_{i,j}\) 表示前 \(i\) 个数,最靠后的 \(=v\) 的数的位置是 \(j\),这种情况下的方案数。考虑转移,我们枚举 \(i\)\(=v\) 还是 \(<v\),如果是 \(=v\),那么就是 \(f_{i-1,j} \to f_{i,i}\)。如果是 \(<v\) 那么就是 \(f_{i-1,j} \times v \to f_{i,j}\)。然后维护一个 \(left\) 数组:对于 \(left_i\) 表示 \(r_j=i\)\((l_j,r_j,p_j)\) 中,\(l_j\) 的最大值(其实就是我们取最强的一个限制)。然后把 \(j<l_j\)\(f_{i,j}\) 全都变成 \(0\)

这些操作用线段树维护即可。

阅读关于"前 k 小" blog & 容斥 blog(没读完)

https://www.luogu.com.cn/article/8lob9dt3
https://www.cnblogs.com/yang-cx/p/16149386.html

另要开始做:https://www.luogu.com.cn/training/682644#information

P11191 「KDOI-10」超级演出

我们考虑记录 \(w_i\) 表示要使得 \(i\) 可以走必须要让 \([w_i,i]\) 的操作执行。处理 \(w_i\) 的话首先对于直接可以走的点 \(w_i=i\) 否则的话就是后继点的 \(w\)\(\mathrm{max}\)。这样做的话复杂度是 \(O(\sum deg)\) 然而 deg 完全可以不停用度数大的点卡掉。因此考虑定 \(B=\sqrt{n}\),然后对于度数: \(\leq B\) 的点直接更新,并且去更新 \(>B\) 的点。

得到了 \(w_i\) 以后直接做就行了,就是要数 \([l_i,r_i]\) 里面满足 \(w_i \leq l_i\) 的数量,直接把询问离线一下然后从前往后做个扫描线就行了。

AT_arc087_d [ARC087F] Squirrel Migration

考虑怎么计数这个 \(\sum dis(i,p_i)\)。看到这种多个 \(dis\) 求和的形式自然的想到看看能不能对边算贡献。考虑记录 \(siz_u\) 表示 \(u\) 子树内的点数,那么答案的上界是 \(\sum_{(u,v),u=father_v} min(siz_v,n-siz_v)\)。考虑只要让重心为根,让 \(i\)\(p_i\) 都不在同一个子树(这里指重心的儿子节点为根的子树)内就可以取到。

现在考虑怎么求方案数,考虑算有 \(i\)\((i,p_i)\) 不合法的,其它数任意匹配的方案数 \(f_i\),那么答案就是 \(\sum_i (-1)^i \times f_i \times (n-i)!\)。你可以发现 \(f\) 是好算的,做个背包即可,转移就是枚举当前的子树里面新增多少对不合法的 \((i,p_i)\) 即可。

AT_abc216_h [ABC216H] Random Robots

首先要算概率,这个显然是假的,直接算方案数,然后除掉 \(2^{nk}\) 即可。

接着看如何计算方案数,现在要刻画的是不相撞,这个是不好刻画的。我们考虑不管这个相撞,直接考虑容斥,假设第 \(i\) 个人最后移动到了 \(y_i\),那么对答案的贡献就是 \((-1)^{p} \prod comb(n,y_i-x_i)\),其中 \(x_i \leq y_i\)\(p\)\(y\) 的逆序对数量(为什么呢,因为 \(n\) 条路径不交方案数:至少 \(0\) 对有交点 - 至少 \(1\) 对有交点 + .....)。

然而显然不能直接枚举 \(y_i\) 来算。考虑我们从 \(v=0,1,...\) 从前往后枚举,然后看 \(v\) 要不要成为一个 \(x_i\)\(y_i\)。然而不能让一个 \(x_i\) 同时对应多个 \(y_i\),因此装压一下即可。

缺一分治

考虑对于 solve(l,r) 这个递归,保证除了 l 到 r 内的全都考虑了,l 到 r 的全都没考虑,那么 solve 到 l=r 的时候就是扣掉 l 的答案。怎么维护这个事情呢?solve 向左边的 [l,mid] 前把 [mid+1,r] 放进去。复原。solve 向右边的 [mid+1,r] 前把 [l,mid] 放进去。

缺点最段路也可以这样做,以 floyd 的第一维作为扣掉那一维。

P6665 [清华集训 2016] Alice 和 Bob 又在玩游戏

P2260 [清华集训 2012] 模积和

P5933 [清华集训 2012] 串珠子

P11427 [清华集训 2024] 绝顶之战

首先可以枚举最后加入的物品集合 \(S\),然后枚举再枚举它们的顺序来检查是否可行。这个复杂度是带阶乘的,考虑优化 check 一个 \(S\) 是否可行:

对于这种划分区间的问题有经典套路,按插入时间对最后的代表顺序的排列建立笛卡尔树,这样就把问题放到了笛卡尔树上,这是一棵树,有很好的子问题归纳性质。

\(w_s\) 表示集合 \(s\)\(a\) 之和。

我们令 \(f_s\) 表示 \(s\) 的点构成一棵(子)树,长度的最大值是多少。这个时候判断就是对于所有子树都能装下 \(f_s>w_s\),并且 \(f_{rt}>m\)

对于一个 \(s\),它的根显然是 \(s\) 中编号最小者。考虑枚举左子树 \(t\),那么右子树就确定了,那么此时长度就是 \(f_{lf}+f_{rt}+a_{x}\),其中 \(x\) 是编号最小者。所有的取 \(max\) 即可。还有一个限制就是对于 \(x\) 之前没选的数 \(a_y\),有 \(f_s \leq a_y\),这个算一下即可。

P11713 [清华集训 2014] 玛里苟斯

P6672 [清华集训 2016] 你的生命已如风中残烛

P8989 [北大集训 2021] 随机游走

P8991 [北大集训 2021] 出题高手

P4137 Rmq Problem / mex

# 2-SAT

简单看了一下,模版题在 Luogu。大概的意思是有 n 个 0/1 变量 w1,w2,...,有 m 个约束形如:(ai,bi,ci,di)表示w[ai]=bi或w[ci]=di。

对于这种 0/1 的东西并且还有约束,考虑直接拆点一手(比如某年 noip 的 t2 就是拆完以后有形如 “相等” 的条件,所以用 dsu 判断)。拆完点以后考虑对于这样的条件:(x,y,z,w) 表示 x=y 的话那么必须 z=w,这类条件我们把 x=y 的点连一个向 z=w 的有向边。那么无解就是图有环。

某神秘 trick

给定⼀张⽆向图,边有边权且为0或1,有些边的边权还没

有确定,现在需要你确定这些边的边权,使得满⾜所有环

的边权的异或值都为0,求⽅案数

考虑给点赋点权,然后边权为相连的两点的点权 xor。这样就转化为点权计数。

与其说这个东西拿来做计数我觉得对于构造的话应该是一个比较巧妙的手法。

AT_agc036_d [AGC036D] Negative Cycle

P7609 [THUPC 2021] 游戏

其实就是让你求 \(a_1,a_2,...,a_m\) 的数量满足:

  1. \(a_1+a_2+...+a_m=n\)

  2. \(a_1 \oplus a_2 \oplus... \oplus a_m \ne0\)

  3. \(a_i \leq lim_i\)

首先把 \(a_ \leq lim_i\) 的条件和 \(a_1+a_2+...+a_m=n\) 的条件先都给限制上,然后对第二个条件正难则反。也就是拿满足两个条件的 - 满足两个条件但是不满足第二个条件的。

前面的东西就拿子集反演 / 广义容斥做一下即可。

现在要计数 \(xor=0\) 的方案数,考虑直接数位 \(dp\)。这里看到两种做法:

记录 \(dp_{pos,stat,add}\) 表示考虑从小到大到 \(pos\) 位,当前满足前 \(i\) 位的数超过(大于)限制的下标集合是 \(stat\),上一位进位到这一位是 \(add\)

记录 \(dp_{pos,stat,add}\) 表示考虑从大到小到 \(pos\) 位,当前满足顶到上界的下表集合是 \(stat\),上一位进位到这一位是 \(add\)

转移是简单的。

P3214 [HNOI2011] 卡农

题意转化后变成在 \(1,2,3,...,2^n-1\) 里面选 \(m\) 个数使得 \(xor=0\)(无序)。求方案数。

然后记 \(f_i\) 表示选 \(i\) 个数(有序)的方案数。转移肯定是要规约子问题的,考虑前 \(i-1\) 个数 \(xor=w\),那么第 \(i\) 个数可以选 \(w\) 就满足了。前 \(i-1\) 个数任选的话就是 \(A(2^n-1,i-1)\)。接下来考虑限制:

  1. \(w=0\)
  2. \(w>0\) 然而 \(w\) 选过了。

是不行的要去掉。

第一种的话方案数就是 \(f_{i-1}\)。第二种的话考虑那个选过的 \(w\) 位置在哪里,那么把它扣掉以后剩下数 \(xor=0\),所以剩下的 \(i-2\) 个数有 \(f_{i-2}\) 种选法,然后对于那个 \(w\) 的位置可以有 \(i-1\) 种选择(你选完以后把 \(f_{i-2}\) 的方案顺序插入),\(w\)\(2^n-1-(i-2)\) 种方案。然后第 \(i\)个数显然就是 \(w\)(因为前 \(i-1\) 个数刚刚已经选定了),已经确定了,不用再多乘。

于是 \(f_i=A(2^n-1,i-1)-f_{i-1}-f_{i-2} \times (i-1) \times (2^n-1-(i-2))\)

结束了。

P9377 [THUPC 2023 决赛] 百合

为什么我的题单进入大量蓝题 /fn。

首先有个想法就是把每个 \(i\)\(i \oplus 2^j\) 连边,边权为 \(0\)。然后跑最段路的时候记一个当前末尾走了多少个 flip 的边。然而这样显然是不太对的,你没法控制不重复 flip 一个位。所以我们考虑在状态里面再加一个 \(pos\) 表示当前考虑从低到高 \(pos\) 位。这样就行了。连的边感觉随便分析一下即可。

然后还是过不了,考虑把 \(0\) 边缩一下即可(每次用 queue 把所有往外走的全 \(0\) 路径到达的点都扫一遍)。

这个故事告诉我们当整体来考虑的时候会算重的话,可以钦定某个顺序来转移。

qoj10012 Make It Regular

翻译一下题,感觉读了很久:

给定一个长度为 \(2n\) 的字符串,问有多少个下标集合 \(S\) 满足你可以任意交换集合 \(S\) 内的括号,使得存在一种方式让字符串合法。保证字符串的左括号数量等于右括号数量。

感觉好简单的题啊,但是为什么一下子没有反应过来呢。
马队的题 /se。

首先是套路的把 ( 改成 1) 改成 -1

显然对于集合 \(S\) 里的括号肯定是左括号放前面,右括号放后面。但是你没法知道 \(S\) 的左括号和右括号的数量,所以似乎没法直接 \(dp\)。然而我们发现因为是左括号在前右括号在后,所以存在一个分界,使得前面都用左括号,后面都用右括号。记录 \(f_{i,j,0/1}\) 表示前 \(i\) 个字符,前缀和是 \(j\),当前在分界前还是分界后,然后每次转移就考虑当前在 \(S\) 中:是否要让当前位成为分界。不在 \(S\) 中:直接让 \(j\) 加减即可。

这样显然不会算错,对于一个 \(S\) 只会在唯一确定的一种划分边界的方式里面计算到。

发现了有趣的 blog

树上算法

数据结构经典手法

笛卡尔树解决排列技数

数据结构神秘手法by gyh

dp神秘手法by gyh

lxl数据结构神秘题记录

高难度模版赛

竞赛图笔记1

竞赛图笔记2

单侧递归线段树

淀粉质和dsu on tree

dmy 讲题

图论 I

矩阵加速dp

静态区间逆序对

吉老师sgt

zr讲题1

zr讲题2

zr讲题3

zr讲题6

zr讲题7

连续段 dp

多用在排列计数上,简单记一下。

主要针对 对于排列的数的大小关系有限制的题 来刻画,考虑从小到大插入所有数。记 \(f_{i,j}\) 表示插入了 \(1\)\(i\),满足当前形成了 \(j\) 个段的情况下(这 \(j\) 个段只是当前待定的,后面可以合并等等),有多少种方案。我们在插入的过程中是不能破坏已有的段的,你不能在段内插入元素,不然显然是会算重的。

那么插入一个数 \(x\) 可能的情况就是:

  1. 插入两个段之间(可能在最左边或者最右边,其实是一样的,你把边界看成段就行)并且不跟两边贴上(其实就是自己开一段),
  2. 插入两个段之间,和其中一边挨着,其实就是在一个段的两边贴上去。
  3. 插入到两个段之间,并且和两边都挨着

在实际题目中需要考虑怎么插是正确的。

题单是这个:Here

P7450 [THUSC 2017] 巧克力

P3542 [POI 2012] PEN-Salaries

有个需要注意的点是权值是 \(1\)\(n\) 的排列,而非说每个数都在 \(1\)\(n\)

\(f_x\) 表示在已有的信息下,我们可以确定的 \(v_x\) 的上界。那么我们考虑令 \(c_x\) 表示 \(f_i \leq x\)\(i\) 的数量,那么 \(x\) 能被唯一确定当且仅当 \(c_{f_x-1}=f_x-1,c_{f_x}=f_x\),证明不难。

P2408 不同子串个数

答案为 \(\frac{n(n+1)}{2}-\sum LCP(S)\),其中 \(S\) 为后缀集合。考虑对于所有后缀的前缀就是字符串的所有子串,然后就能理解了。

后面的东西要么容斥,要么按字典序排完以后直接对相邻求即可。

posted @ 2025-08-27 13:26  v1ne0qrs  阅读(25)  评论(0)    收藏  举报