给定一张有向图图,有若干个关键点,求所有关键点中距离最短的一对的距离。
n,m≤105
每次选取两个点集 A 和 B ,以 A 为起点,跑一边最短路,则 minb∈Bdis[B] 为 mina∈A,b∈Bdis(a,b) 。
考虑目标点对 a=b , a 中的一位二进制和 b 中的一位二进制不相同,所以每次通过二进制上的某一位划分 A 和 B ,跑 logn 次最短路即可。
注意有向图,每次要从 A 跑一次,从 B 跑一次
提交记录
有一棵「模板树」,下称 树A 。
有一棵「大树」,下称 树B 。
最初,树B和树A是一样的。
每次操作,把树A中以某个点为根的子树复制到树B的某个点下(树A中的那个点成为新的树B的儿子),然后按在原树中的编号大小顺序重新标号。
然后若干次询问,每次询问两个点之间的距离。
询问树上的距离,常用的操作是lca+深度,这里也这么做。
考虑每次操作,形成一个新的「块」,所有的块构成了一棵树,我们维护这棵树上的深度和lca。
重新标号用主席树处理(以 u 为根的子树中编号第 i 小的节点,或者以 u 为根的子树中 x 第几小),在 dfn 序列上做区间第 k 小即可。
树A中的编号与树B中的编号极容易弄混,需要认真对待。
提交记录 (loj Ofast+少爷机就是好)
n,m≤105
给定一棵树和若干个树上的点,每次可以在 u 用 wu 的代价覆盖距离 u 小于等于 d 的点,求覆盖所有的关键点需要的最小代价。
对于每个点,设 f[u][i] 表示还要满足还要向下覆盖 i 层最小代价, g[u][i] 表示可以向上覆盖 i 层最小代价。
那么有,初始化
g[u][0]=w[u]⋅Important?(u)
i>1,g[u][i]=w[u]
转移
f[u][i]=f′[u][i]+f[v][i−1]g[u][i]=min(g[u][i]+f[v][i],f′[u][i+1]+g[v][i+1])g[u][i]=j>imin(g[u][i],g[u][j]f[u][i]=j<imin(f[u][i],f[u][j]f[0]=g[0]
(关于 g[u][i]←f′[u][i+1]+g[v][i+1] 的转移解释)
1 2 3 4 5 6 7 8 9 10
| U 还能向上 D 还能向下
[u] (U i D i) +--------------------+ --- (Total: i+1) | | | [v] (U i+1) [w] (D i-1) | . | . | . | ---
|
提交记录
有一张图,问有多少种加边方案,使得加边后的图是一个仙人掌(一条边至多在一个简单环中)。
若最初的图不是仙人掌,返回 0 。
否则删去所有的环边,得到一个森林,考虑每棵树的情况。
对于每棵子树,强制选择其中的一个点可以向上连边(不连的情况就是其向它的父亲连一条重边),设为 f[u]
对于点 u 考虑儿子 v 中的所有向上连边的点,他们有两种方案:
- 连向 u;
- 连向其他的 v 中的向上连边的点。
我们用 h[i] 表示 i 个点按以上方案连边的的方案数:
h[i]=+h[i−1](i−1)h[i−2] 这个点连向u 从剩下i−1个点中选一个
所以有
f[u]=+=h[deg[u]]v∈son[u]∏f[v]v∑h[deg[u]−1] f[v]w∈son[u],w=v∏f[w]h[deg[u]+1]v∈son[u]∏f[v] 选择u作为向上连边的点 选择v作为向上连边的点
但是对于根,由于不能选择其作为向上连边的点(为什么?仔细想一下,其不能向上连边,向下的情况都已经计算过了)。
所以
f[root]=h[deg[root]]v∈son[root]∏f[v]
提交记录
有若干个篮子,每个篮子要么不放东西,要么放 [ai,bi] 个东西,且要大于之前所有篮子放东西的个数。
n≤500,ai≤bi≤109
由于 ai,bi 非常大,考虑离散化,形成若干个区间 [ai′,bi′) 。
考虑 i 在区间 j 内选择,k 是第一个在区间 j 之前选择的, k+1⋯i 都在区间 j 内选择,1⋯k 都在区间 1⋯j 内选择
令其的方案数为 f[i][j] (强制 i 选择, k<i 随意)。
那么有 f[i][j]=∑k=0i−1∑l<jf[k][j] sum(k+1,i)
其中 sum(k+1,i) 为从 k+1 到 i 中,在区间 j 内选择的方案数(如果无法满足就不选, i 必须选)。
令 c=cnt(j,k+1⋯i) ,即 k+1⋯i 中可以取到区间 j 的方案数,那么 sum(k+1,i)=(cb′[j]−a′[j]+c−1)
提交记录
求 222⋯modp
有扩展欧拉定理,对于任意 b≥φ(p)
ab=a(b modφ(p))+φ(p)(modp)
显然 222⋯>>φ(p)
f(p)={02f(φ(p))+φ(p) mod pp=1otherwise
给定一个 01 串,每次操作,给定一个 i 翻转所有 1≤j≤i,j∣i ,要让全为 0 。
若当前能在 k 步之内完成操作,则进行这个操作,否则随机进行一个操作,求期望。
n≤105
首先考虑初始状态的最优策略,由于一个 i 不会被 j<i 修改,所以可以从大到小进行贪心操作,设这时的最少操作次数为 c ,操作的顺序无关紧要。
考虑 dp ,令 f[i] 表示当前可以最少恰好 i 步完成操作的期望。
那么对于 i≤k ,有 f[i]=i 。
否则 f[i]=nif[i−1]+nn−if[i+1]+1 ,有 ni 的概率进行正确的操作,剩下 nn−i 的概率进行错误的操作,可以证明,至少需要再操作一次(按回来)。
对于 f[i] 的转移,推式子,令 f[i]=f[i−1]+b[i] :
f[i]0b[i]===ni(f[i]−b[i])+nn−i(f[i]+b[i+1])+1−nib[i]+nn−ib[i+1]+1i(n−i)b[i+1]+n
提交记录
有 n 个人,m 门课 ,和一个人 B神 ,有 k 个人的每门课的成绩都比B神低(小于等于),同时每门课有最高分 Ui 最低分 1,B神的排名是 Ri (有且仅有 Ri−1 个人分数大于B神),求满足以上情形的方案数。
考虑 dp 。
设 f[i][j] 为考虑前 i 个人,有 j 个人每门课的分数都比 B 神低,那么有如下转移
f[i][j]=k=j∑n−1f[i−1][k](k−jk)(Ri−1−(k−j)n−k−1)g[i]
其中 g[i] 为对于第 i 门课,选定有谁分数大于B神的情况下的方案数。
考虑这门课有谁的分数比 B神高,那么他就被从“比B神低”中除名了。
考虑上一次有 k 个人,那么 (k−jk) 为从其中选出有多少人分数第一次比B神高,由于一共需要 Ri−1 个人,所以还要从已经比B神高的 n−k−1 个人中选 Ri−1−(k−j) 个人。
考虑怎么求 g[i] ,枚举B神的分数 j ,Ri−1 个人分数在 j+1⋯Ui 中,剩下 n−Ri 个人分数在 1⋯j 中:
g[i]=j=1∑Ui(Ui−j)Ri−1 jn−Ri
因为 Ui 很大,不能暴力求,发现 g[i] 是一个关于 Ui 的 n 次( ∑xn 为 n+1 次多项式)多项式,即:
G(x)=j=1∑x(Ui−j)Ri−1 jn−Ri
用拉格朗日插值即可。
提交记录
求 ∑i=0∞(ik+rnk) ,其中 n≤109,r<k≤50 。
也就是求 ∑i mod k=r(ink) 。
考虑二项式定理 (ink)=[xi](∑i(ink)xi)=[xi](1+x)nk 。
也就是要求 ∑i mod k=r[xi](1+x)nk ,考虑使用循环卷积,把超过 k 的项卷回去,即 H(x)=∑i=0k−1∑j=0k−1[xi]F(x)⋅[xj]G(x)⋅xi+j mod k
对 (1+x)nk 使用循环卷积快速幂即可,最后答案就是求出来的 xr 的系数,时间复杂度 O(k2(lognk))
(注意当 k=1 时,初值是 2 ,不是 1+x )
提交记录
有 n 个点,n−1 个限制,对于每个限制,要求第 i 个点要排在第 j 个点之前或者之后,保证不存在两个点不相关(不能划分为两个点集 A, B, ∀a∈A,b∈B,无限制(a,b) ),求排列方案数。
不考虑限制的顺序的话,这就是一棵树,我们考虑用树形 dp 来求。
令 f[u][i] 为 u 在已经处理的 u 的子树内,排名为 i 的方案数,每次就是要把 f[v][k] 合并到 f[u][i] 上。
先考虑 v 要在 u 之前求。
考虑 v 中有 j 个点要被放在 u 之前,有 j≥k ,即必须让 v 放在 u 之前。(有一些问题,稍后讨论),
即
i=1⋯siz[u],j=0⋯siz[v]f[u][i+j]←f′[u][i](ji+j−1)(siz[v]−jsiz[u]−i+siz[v]−j)(k=1∑jf[v][k])
其中 siz[u] 为 u 已经处理过的点数,siz[v] 为 v 的点数,(ji+j−1) 就是选前 j 个要被放在哪些地方,(siz[v]−jsiz[u]−i+siz[v]−j) 就是选后 siz[v]−j 个要被放在哪些地方。
最后要 siz[u]+=siz[v] 。
假如 v 要放在 u 之后,也是同理:
f[u][i+j]←f′[u][i](ji+j−1)(siz[v]−jsiz[u]−i+siz[v]−j)(k=j+1∑siz[v]f[v][k])
现在有一个问题,为什么这么讨论是正确的:
每次插入时,u 原先的排列和 v 原先的排列中的相对顺序并没有改变,所以可以保证符合题目要求,同时也可以枚举到所有的相对位置的可能性(???我也不太懂,感性理解一下)。
(说一个可能会疑惑的点,考虑如下的:
考虑 wtv
和 u
,这种情况是不能转移到 wvut
的,但是 wvut
是可以从 wvt
转移过去的)
提交记录
给定一个数字串,每次交换两个位置,然后求逆序对个数。
设 gt(l,r,x) 为 l⋯r 中大于 x 的数的个数,lt(l,r,x) 同理。
考虑交换 l<r ,那么对于在 l 之前或者 r 之后的位置没有影响,而中间的贡献是 −gt(l+1,r−1,ar)+gt(l+1,r−1,al)−lt(l+1,r−1,a[l])+gt(l+1,r−1,a[r])−[al>ar]+[ar>al] 。
考虑维护 gt 和 lt ,用线段树套平衡树,即线段树每个节点维护一个 FHQTreap 即可。
提交记录
求长为 n ,每个数在 1⋯m ,和为 p 的倍数,且有一个数为质数的数列的方案数。
n≤109,m≤2×107,p≤100
考虑使用模 p 下的多项式,和容斥。
令 [xi]Fl(x) 为用 1⋯m 组成长度为 l ,和模 p 为 i 的方案数,[xi]Gl(x) 为用 1⋯m 中的合数组成长度为 l ,和模 p 为 i 的方案数。
那么答案就是 [x0]Fn(x)−[x0]Gn(x) 。
考虑如何求 Fl(x) 和 Gl(x) 。
若 l=1 :
i∈[0,p−1],[xi]Fl(x)=j∈[1,m],j mod p=i∑1i∈[0,p−1],[xi]Gl(x)=j∈[1,m],j mod p=i,j∈P∑1
否则,合并两个长度为 a 和 b 的数列,显然可以从两边选择任意一个数列,然后和相加即可。
考虑循环卷积,令 l=a+b,a,b<l:
Fl(x)=i∈[0,p−1]∑j∈[0,p−1]∑[xi]Fa(x) [xj]Fb(x) x(i+j) mod p
然后用快速幂即可。
提交记录
有一个序列 ai ,求
i,j∈[1,n],i≤j, xor(∑a[i⋯j])
考虑计算所有可能的 a[i⋯j] 的个数,然后答案就是所有出现奇数次的数的异或和。
令 fx 为所有可能的 a[i⋯j] 中,x 的出现次数。
令 gx 为前缀和 a[1⋯i] 中 x 的出现次数。
由于有 a[i⋯j]=a[1⋯j]−a[1⋯(j−1)] ,所以有 fi=∑j=0m−igjgi+j 。( m=a[1⋯n] )
考虑进行变换
fifm−i′fm−i′fi′====j=0∑m−igjgi+jj=0∑i′gjgj+m−i′j=0∑i′gjgi′−j′j=0∑i′gjgi′−j′i←m−i′gi′←gm−ifi′←fm−i
就可以卷积了。
提交记录
有两个字符串 S 和 T ,问 S 有多少个子串更改不超过 3 个字符(长度不变)能和 T 相同,其中 S 和 T 都由 A, T, C, G
四个字符组成。
分别考虑四个字符:
令上文中的 S 为 S(0) ,T 为 T(0) 。
设当前考虑的字符是 ch ,那么 Si=[Si(0)=ch],Ti=[Ti(0)=ch]
令 Pi 为 S 以 i 结尾,长度 ∣T∣ 的子串只考虑这个字符的情况下的匹配个数:
PiPiPi===j=0∑m−1Tj Si−(m−1)+jj=0∑m−1Tm−1−j′ Si−(m−1)+jk+l=i∑Tl′ SkTj=Tm−1−j′l=m−1−j, k=i+(m−1)+j, 并且不用考虑范围
卷积即可。
提交记录
有一个定义在非负整数之间的 ⊆ ,a∧b=a⇔a⊆b
考虑在一个无限大的空间中:
x⊆x′⇒(x,y,z)→(x′,y,z)
y⊆y′⇒(x,y,z)→(x,y′,z)
z⊆z′⇒(x,y,z)→(x,y,z′)
其中有若干个点不能经过,求到某个点的方案数,不能经过的点数 n≤10000 。
一个套路,求不经过某些点的方案数,可以用如下的 dp 解决:
考虑一条非法的路径,枚举它第一次经过的不能经过的点。
f[i] 为不经过不能经过的点到 i 的方案数,其中 g(j,i) 为从点 j 出发,不考虑不能经过的点的方案数。
f[i]=g(0,i)−j=i∑f[j] g(j,i)
现在就要求 g(j,i) 怎么求。
每一次移动,都是在某些位上置 1 ,可以发现,路径数目只与要添加的 1 的个数有关。
令 h[i][j][k] 为 x,y,z 上分别要置 i,j,k 个 1 的方案数,分别考虑从三个方向转移,那么有:
h[i][j][k]=i′=0∑i−1h[i′][j][k](i′i)+j′=0∑j−1h[i][j′][k](j′j)+k′=0∑k−1h[i][j][k′](k′k)
提交记录
给定 n×n 的 ai,j 和 bi,j ,选 n 个位置,每行每列有且只有一个,使得
∑k=1nbxk,yk∑k=1naxk,yk
最大 。
分数规划的常用套路:
∑k=1nbxk,yk∑k=1naxk,yk∑k=1nbxk,yk∑k=1naxk,ykk=1∑naxk,yk−(mid+Δ)k=1∑nbxk,ykk=1∑n(axk,yk−(mid+Δ)bxk,yk)k=1∑n(axk,yk−mid⋅bxk,yk)=====c≥mid(mid+Δ)00Δk=1∑nbxk,yk
若存在一种方案使得 ∑k=1n(axk,yk−mid⋅bxk,yk)≥0 ,那么 Δ≥0 ,所以能取到 c≥mid 。
考虑使用最大费用流,源点向每一行连边,每一列向汇点连边,第 i 行向第 j 列连费用为 ai,j−mid⋅bi,j 的边 ,然后判断最大费用是否大于等于 0 即可(容量为 1 )。
提交记录
给定两个序列 xi,yi ,要求支持如下操作:
-
输入 l,r ,求
a=∑l≤i≤r(xi−xˉ)2∑l≤i≤r(xi−xˉ)(yi−yˉ)
其中 xˉ 为 xl⋯xr 的平均数,定义为 r−l+1∑l≤i≤rxi ,yˉ 为 yl⋯yr 的平均数,定义为 r−l+1∑l≤i≤ryi
-
输入 l,r,s,t ,令 ∀ l≤i≤r, xi←xi+s, yi←yi+t 。
-
输入 l,r,s,t ,令 ∀ l≤i≤r, xi←i+s, yi←i+t 。
序列问题,考虑用线段树解决,先考虑操作 1,推式子:
a=====∑i(xi−xˉ)2∑i(xi−xˉ)(yi−yˉ)∑i(xi−xˉ)2∑i(xi−xˉ)(yi−yˉ)∑i(xi−xˉ)2∑ixiyi−∑ixˉyi−∑iyˉxi+∑ixˉyˉ∑i(xi−xˉ)2∑ixiyi−xˉ∑iyi−yˉ∑ixi+xˉyˉ(r−l+1)∑ixi2−2xˉ∑ixi+xˉ2(r−l+1)∑ixiyi−xˉ∑iyi−yˉ∑ixixˉyˉ(r−l+1)
发现,我们需要用线段树维护这些东西:∑xiyi,∑xi,∑yi,∑xi2 。
同时我们还需要支持两个修改操作,分别是 xi,yi=i 和 xi+s,yi+t ,第 3 个操作可以由这两个操作组合而成。
-
∀ l≤i≤r:xi=yi=i
i∑xiyi=i∑xixii∑xi=i∑yi←←i∈[l,r]∑i2=(i∈[1,r]∑i2)−(i∈[1,l−1]∑i2)=6r(r+1)(2r+1)−l(l−1)(2l−1)2r(1+r)−l(l−1)
-
∀ l≤i≤r:xi←xi+S,yi←yi+T
i∑x′ii∑y′ii∑x′i2i∑x′i y′i←←←←i∑(xi+S)i∑(yi+T)i∑(xi+S)2i∑(xi+S)(yi+T)====(i∑xi)+(r−l+1)S(i∑yi)+(r−l+1)T∑xi2+2S∑xi+(r−l+1)S2∑xiyi+S∑yi+T∑xi+(r−l+1)ST
提交记录
考虑一个长度为 n 的序列互不相同 ai ,要求有多少个 ai 的不降子序列 ab1,ab2⋯abk,k≥2 满足:
i=2∏k(abiabi−1)mod2>0
数据范围:n≤211986,ai≤233333 。
原式就是要求每个 (abiabi−1)mod2=1 。
因为有 mod2 这个条件,考虑使用卢卡斯定理。
(ba)modp=(b/pa/p)(bmodpamodp)modp
可以发现,当 p=2 的时候每一次进行这个操作,就是把最低一位拆出来。
所以令 a=⟨xt,xt−1,…,x0⟩2,b=⟨yt,yt−1,…,y0⟩2 ,那么
(ba)mod2=(ytxt)(yt−1xt−1)⋯(y0x0)mod2=1⇓(ytxt)=(yt−1xt−1)=⋯=(y0x0)=1
因为 xi,yi∈{0,1} ,而
(00)=(01)=(11)=1(10)=1
不难发现,这就要求在二进制下 b 要是 a 的子集。
回到题目中,∀ 2≤i≤k,abi⊂abi−1
令 fi 表示以 i 结尾的,长度大于 2 的满足如上条件的的方案数,那么:
j⊂i, fj←fj+fi+1
要加 1 是因为可以 i 开始,注意可能不存在某个 at=j
每次统计答案 ans←ans+ai
提交记录
给定一个 h×w 的矩阵,每个格子能填上一个 1⋯m 的数,同时有 n 个限制,每个限制给出一个子矩阵,要求子矩阵的最大值为 v ,求方案数。
h,w≤104,n≤10
最大值为 v 较难处理,因为要求至少有一个位置取到 v ,考虑容斥:用1⋯v的方案数−用1⋯v−1的方案数 。
h,w 较大,而 n 有较小,考虑对其进行离散化,得到若干个子矩阵(左上开,右下闭),每个子矩阵有最大值限制,并用状压记录下,若取到这个最大值,有哪些限制(有取到最大值)能被满足。
然后枚举子矩阵 i 和已经满足的限制 j ,令 x 为不取最大值的方案数, y 为取到(至少一个)最大值的方案数,能满足 s 的限制,那么:
fi,j←fi−1,j+xfi,j∪s←fi−1,j+y
并且 x=(v−1)area,y=varea−v ,其中 area 为其的面积。
提交记录
给定非负整数序列 a ,初始长度为 n ,有若干个操作:
-
给定 x ,在序列末尾添加 x ,n←n+1
-
给定 l,r,x 求
l≤p≤rmaxap⊕ap+1⊕⋯⊕an⊕x
考虑操作2,可以用前缀和 si,变为:
l≤p≤rmaxsp−1⊕sn⊕x=l−1≤p≤r−1maxsp⊕sn⊕x
sn⊕x 知道,要求 sp 异或上它最大,这是一个传统的问题,可以用 trie 解决。
考虑怎么满足 l−1≤p≤r−1 的限制:
先考虑 p≤r−1 ,可以采用主席树的思想,即可持久化 trie ,每次插入一个新的数,都新开一棵 trie ,询问时就在第 r−1 棵 trie 上贪心即可。
再考虑 l−1≤p ,对 trie 的每个节点记录最新的节点编号 newest ,若 newest<l−1 ,那么显然不满足要求。
提交记录
给定一张 n 个节点的图,有 k 个时间,有 m 会在某个时间出现,在某个时间消失,求每个时间内这个图是否是二分图。
先介绍一下如何判断一个图是二分图,使用并查集:
把每个点拆成两个:u 和 u+n 。
每次连边 u,v ,先检查若 u 和 v 在同一个并查集内,则不是二分图,否则合并 (u,v+n) 和 (v,u+n) 。
线段树分治可以处理这样的一个问题:有若干个操作,每个操作只在 l⋯r 的时间内有效,同时还有一些询问,询问某个时间点内操作的贡献。
线段树分治将时间轴放到线段树上,每进入一个节点,处理在这个节点的 l,r 内会生效的操作,离开这个节点时,撤销 这些操作(你很难 删除 这些操作带来的贡献,比如对于这题的并查集),若到了叶节点,询问即可。
回到这道题,我们建出一棵线段树,然后用类似区间操作的方法,把一条边拆成若干份,挂在若干个线段树节点(这条边要在这个线段树节点对应的时间内完全生效)上。
然后询问,到每个节点把这个节点上所有的边加入并查集(因为要撤销,所以不能路径压缩,只能按秩合并),并判断是否符合要求,若否,这个节点的子树中也不可能符合要求了。否则继续递归,到叶节点时设置答案,然后每个节点离开时,按倒序撤销边的贡献即可。
提交记录
给定一个无向连通图和若干个小集合(集合大小 c≤4 ),每个小集合包含一些边,对于每个集合,你需要确定将集合中的边删掉后改图是否保持联通。集合间的询问相互独立。
用线段树分治,处理出每个边不被删掉的时间段,放到线段树上。
然后dfs线段树,用并查集维护连通性,进去的时候加入,离开的时候撤销,到每个叶节点判断是否联通( dsu.size[dsu.get(1)] == n
)。
提交记录
一棵 n 个点的有根树,其中 1 号点是根节点。并且每个点上的颜色不同。
定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。
进行这几种操作:
1 x
表示把点 x 到根节点的路径上所有的点染上一种没有用过的新颜色。
2 x y
求 x 到 y 的路径的权值。
3 x
在以 x 为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。
不难发现,每种颜色都是一条从上到下的链,令 val[x] 为 x 到根的这条路径的权值,那么操作2就是 val[x]+val[y]−2⋅val[lca(x,y)]+1 (需要 +1 是因为 −val[lca(x,y)] 会把 lca 所在的那段颜色扣掉),操作三就是 u 子树中做 maxval[v] ,可以用 dfn + 线段树维护。
考虑用 lct 维护操作1 。lct 用一棵 splay 维护一段链,这里强制用一棵 splay 维护一段颜色,发现一个节点的 val 就是这个节点到根的虚边数量 +1 ,并且 access 操作强制把一段链到根的链变成一棵树,那么我们就可以用其的 access 操作来实现操作1 。
具体做法:
1 2 3 4 5 6 7 8 9
| void access(int u) { for (int v = 0; u; v = u, u = tr[u].fa) { splay(u); if (tr[u].ch[1]) seg.modify_tr(findrt(tr[u].ch[1]), 1); if (v) seg.modify_tr(findrt(v), -1); conn(u, v, 1); } }
|
时间复杂度不会证,是均摊 O(log n) 的
提交记录
给定 n 个点,有若干个操作,一种是添加一条边,另一种是问经过某条边的路径数目有多少。保证这个图任意时刻都是森林。
森林,加边,lct 没跑了。
询问操作就是两个点的虚儿子个数 +1 乘起来。
注意 access 操作的时候维护虚儿子个数即可。
提交记录
有一个错误的树状数组操作,单点加 1,区间查询(前缀和)(对 2 取模),只不过代码中把修改和查询操作的下标更新的正负号写反了。有两种操作,若干次,第一种是在 [l,r] 中等概率选取一个 x ,单点修改,第二种是询问某个区间得到正确结果的概率是多少。
不难发现,对 2 取模单点加 1 就是异或,这个错误的树状数组其实实现的是查询后缀和。
那么要求的:al⊕al+1⊕⋯⊕ar ,实际求的: al−1⊕al⊕⋯⊕an⊕ar⊕ar+1⊕⋯⊕an=al−1⊕⋯⊕ar−1 。
二者要相等,及 al⊕⋯⊕ar⊕al−1⊕⋯⊕ar−1=al−1⊕ar−1=0 。
即所求的是 al−1=ar−1 的概率。
考虑用树套树来维护 al=ar 的概率。
对于第一种操作 (L,R) :
令 len=R−L+1 。
对于所有 l<L≤r≤R ,有 len1 概率翻转。
对于所有 L≤l≤R<r ,有 len1 概率翻转。
对于所有 L≤l≤r≤R ,有 len2 概率翻转。
同时需要考虑一种特殊情况,若查询时 l=1 (原操作求”前缀和“时,若 x=0 返回 0 ):
(a1⊕⋯⊕ar)⊕(0⊕ar⊕⋯⊕an)
即前缀和和后缀和相不相等。
对于所有 r<L≤R ,有 1 的概率翻转。
对于所有 L≤R<r ,有 1 的概率翻转。
对于所有 L≤r≤R ,有 1−len1 的概率翻转(有 len1 的几率恰巧碰到 r ) 。
现在思考一下实现细节:
树套树对于每个点,用 l,r 维护 al=ar 的概率。
有一棵线段树,对于线段树的每一个区间,都开一个线段树。对于区间修改操作,对每个完全覆盖的区间,在对应的线段树上继续操作。对于单点查询,要注意累加所有覆盖这个点的区间的线段树上的贡献。
合并两个概率的函数:merge(x,y)=xy+(1−x)(1−y) (有可能都翻转,也有可能都不翻转)。
提交记录