我的CF账号:guozexin
如果题解有哪些疑惑的地方,可以直接在CF上找我的代码查看细节
这道题目乍一看很花哨,但和位运算有关的题目,手玩一下就可以把原题的操作换作一个很简单的操作。
本题中其实就是在同一位上选择k个1,使这k个1都变成0,若要使一位上的1都变成0,那这一位上1的个数需是k的倍数,所以我们对每一位上的1的个数取gcd,得到k,若k成立,则k的因数也一定成立,输出k的所有因数即可
青蛙爬井问题
在初学OI时也有一道这样的青蛙爬井的题目,当时a和b都是固定的,推出数学式子即可
而这道题的a和b都不固定,且向上爬的高度也不一定是a。可以想到最暴力的做法直接去bfs,找出爬出井的最短时刻,但显然由于向上爬的高度不确定,bfs的复杂度会极大
对于上述问题,有两种解决方法
用并查集来维护一下,将跳过的点和它上面的点合并在一起,因为这个点既然已经跳过,那之后再跳到这个点,答案一定会更劣,所以我们枚举向上跳的时候就可以跳过这个点,用并查集搞下来每个点只会访问一次,复杂度是O(n)的。
这个思路与前几天模拟赛中的一个扫雪的题思路很类似,也是通过并查集来优化掉冗余操作,从而使时间大大增加
另一种解决做法就是依然是正常的bfs,但在建图时用倍增或线段树来优化建图即可
这个题目的一个小trick:青蛙最后一个白天直接就跳出井了,而不会再往下掉,所以我们将今天白天与昨天晚上一起进行处理,而不是将今天白天与今天晚上一起处理
考虑暴力的做法,用树状数组维护逆序对个数,把每一个b放到a中找它最合适的位置,复杂度为 O ( m n l o g ( n ) ) O(mnlog(n)) O(mnlog(n)),显然过不去
设 p i p_i pi表示 b i b_i bi在 a a a中的位置,即当 b i b_i bi恰好在 a j a_j aj之前时, p i = j p_i=j pi=j
存在一个性质,即将 b b b从小到大排序后, p i p_i pi单调递增。证明的话考虑反证法,将两个 b b b调换顺序,答案显然会更劣
根据这个性质进行整体二分,先处理出 b m i d b_{mid} bmid的位置,即 p m i d p_{mid} pmid,然后将 b b b从 m i d mid mid处划分开,将值域也从 p m i d p_{mid} pmid处划分开,继续进行处理
这样即可高效的优化上述暴力过程,得到每一个 p i p_i pi后,构造出最终的序列 c c c,树状数组+离散化 求一下逆序对个数即可
总复杂度为 O ( ( n + m ) ∗ l o g ( n + m ) ) O((n+m)*log(n+m)) O((n+m)∗log(n+m))
看大部分神仙们这道题写的都是线段树做法,蒟蒻没读懂代码,只好啃官方英文题解
先将人按照 m a x ( a i , s i ) max(a_i,s_i) max(ai,si)从小到大排序。如果 m a x ( a i , s i ) max(a_i,s_i) max(ai,si)相等,则按 s i s_i si从小到大排序
证明:(来自洛谷题解 0htoAi)
多个基础数据结构加起来就不基础了
这道题用到了一个类似于映射的思想吧
很容易通过题目归纳出我们要求的结果即为
∑ i = l + x k , l ≤ i ≤ r , x ∈ Z m i n l ≤ j ≤ i a j \sum_{i=l+xk,l\leq i\leq r,x\in Z} min_{l\leq j\leq i}\;a_j ∑i=l+xk,l≤i≤r,x∈Zminl≤j≤iaj
那我们会发现,对于某一个询问,有一些 a i a_i ai是根本不可能作为答案的,例如要玩 6 6 6天,一张票能玩 2 2 2天,第 6 6 6天的票价无论再便宜,我都不可能在这一天去买票,因为已经没有价值了
所以,我们可以把右端点收缩到一个与左端点在模 k k k的意义下同余的一个数
即 r = l + k ⌊ r − l k ⌋ r=l+k\lfloor \frac{r-l}k \rfloor r=l+k⌊kr−l⌋
预处理出一个 b b b数组, b i b_i bi表示 a i − k − a i a_{i-k}-a_i ai−k−ai中的最小值(利用单调队列求解)
再进行 d p dp dp, d p i dp_i dpi表示 m i n ( b i ) + m i n ( b i , b i + k ) + m i n ( b i , b i + k , b i + 2 ∗ k ) + . . . + m i n ( b i , b i + k , . . . , b i + x k ) ( x ∈ Z , i + x k ≤ n ) min(b_i)+min(b_i,b_{i+k})+min(b_i,b_{i+k},b_{i+2*k})+...+min(b_i,b_{i+k},...,b_{i+xk})(x\in Z,i+xk\leq n) min(bi)+min(bi,bi+k)+min(bi,bi+k,bi+2∗k)+...+min(bi,bi+k,...,bi+xk)(x∈Z,i+xk≤n)
不难发现,这样其实是把所有数字分成了 k k k组,分别对这 k k k组进行 d p dp dp, d p dp dp的过程可以这样倒序求解:
d p i = d p p o s + ( p o s − i ) ∗ b i ( p o s dp_i=dp_{pos}+(pos-i)*b_i(pos dpi=dppos+(pos−i)∗bi(pos为第一个在 i i i之后且 b p o s < b i b_{pos}
至于怎么找右侧第一个小于 b i b_i bi的数,就是单调栈的基本操作了
总结一下我们最后的要求的答案,实际上就是 a l + m i n ( b l + k ) + m i n ( b l + k , b l + 2 ∗ k ) + . . . + m i n ( b l + k , . . . , b l + x k ) ( x ∈ Z , l + x k ≤ r ) a_l+min(b_{l+k})+min(b_{l+k},b_{l+2*k})+...+min(b_{l+k},...,b_{l+xk})(x\in Z,l+xk\leq r) al+min(bl+k)+min(bl+k,bl+2∗k)+...+min(bl+k,...,bl+xk)(x∈Z,l+xk≤r)
这下子就可以发挥 d p dp dp数组的作用了,我们可以利用一个后缀和的操作,来求解 a l a_l al后面的式子
但事情还没有这么简单,因为你在取 m i n min min,所以不可以简简单单的用后缀和来实现,那如果我取到一个在 [ L , R ] [L,R] [L,R]中最小的 b p o s b_{pos} bpos的位置呢,这样就可以进行求解了,答案即为 a l + d p l + k − d p p o s + ( R − p o s + k ) / k ∗ b p o s a_l+dp_{l+k}-dp_{pos}+(R-pos+k)/k*b_{pos} al+dpl+k−dppos+(R−pos+k)/k∗bpos
而这个最小的位置怎么求呢,又到了ST表的基本操作了,和 d p dp dp数组求解过程一样,依然是把 k k k组分别拎出来求解,也就是我们可以做一个映射版的ST表,但尤其需要注意在映射过程中+k,*k,/k等一系列操作的实际含义
折半搜索好题
根据折半搜索的思想,首先,我们必须会做出来O(1e6)的做法,也就是O(n)怎么做这个题,我们可以直接暴力dfs去按字典序搜索出每一个范围内的数字,算答案就行
将12位数拆成两半,对两半的六位分别进行上述的O(n)搜索,考虑存储信息与合并,我们可以先求出 a a a的逆排列 b b b数组
例如:
当 n = 12 n=12 n=12时
a : 1 10 11 12 2 3 4 5 6 7 8 9 a:1\;10\;11\;12\;2\;3\;4\;5\;6\;7\;8\;9 a:110111223456789
b : 1 5 6 7 8 9 10 11 12 2 3 4 b:1\;5\;6\;7\;8\;9\;10\;11\;12\;2\;3\;4 b:156789101112234
数列满足: a b i = b a i = i a_{b_i}=b_{a_i}=i abi=bai=i
所以求解 ∑ i = 1... n ( ( i − a i ) m o d p ) = ∑ i = 1... n ( ( b i − a b i ) m o d p ) = ∑ i = 1... n ( ( b i − i ) m o d p ) \sum_{i=1...n}((i-a_i)\;mod\;p)=\sum_{i=1...n}((b_i-a_{b_i})\;mod\;p)=\sum_{i=1...n}((b_i-i)\;mod\;p) ∑i=1...n((i−ai)modp)=∑i=1...n((bi−abi)modp)=∑i=1...n((bi−i)modp)
为什么要求这个 b b b数组呢,因为它满足一个性质:
b v a l x x x x x x = b v a l + b x x x x x x ′ b_{valxxxxxx}=b_{val}+b'_{xxxxxx} bvalxxxxxx=bval+bxxxxxx′
b b b和 b ′ b' b′分别指从两半搜索出来的顺序
所以贡献可拆为 ( ( b v a l − 1 0 6 ∗ v a l ) + ( b x x x x x x ′ − x x x x x x ) ) m o d 998244353 ((b_{val}-10^6*val)+(b'_{xxxxxx}-xxxxxx))\;mod\;998244353 ((bval−106∗val)+(bxxxxxx′−xxxxxx))mod998244353
所以我们可以维护后面的一项 ( b x x x x x x ′ − x x x x x x ) (b'_{xxxxxx}-xxxxxx) (bxxxxxx′−xxxxxx),求出当有 i i i个 x x x时,所有这些项的累加和 s u m i sum_i sumi
本题的难点在于取模的第一个 998244353 998244353 998244353,若没有此条件,答案必然为0,加上此条件后,有些相加后大于 m o d mod mod的数字就要减去 m o d mod mod,所以我们可以 l o w e r b o u n d lower bound lowerbound一下,找到相加超出 m o d mod mod的数字有多少个,把结果减去个数 ∗ m o d *mod ∗mod即可
一道水题,要 a a a的字典序最小,那长度越小越好,所以我们找到字典序最小的一个字母,将它从原串中剥离出来作为 a a a串,剩下的部分作为 b b b串即可
观察一下这道题数据范围和样例,不难猜测到序列变化到一定次数就不会再发生改变了,貌似是每一次变化都会少一组数,所以变化次数最多是 n n n次,所以就可以存下每一次变化的每一个值, O ( 1 ) O(1) O(1)回答即可
结论题:如果这个序列中有至少一个位置上 a i a_i ai可以整除小于等于 i i i 的所有数,那么一定无解。 反之一定有解。
证明很简单,因为你可以选择删除的顺序,所以若满足条件,采用一种贪心策略一定能将全部消除完
题目很简单,就是想办法构造出n
我们不要看到模运算就想同余之类的数论算法,其实可以考虑一下模运算的最基本性质,比如这道题中,分成两种情况讨论:
当 x > y x>y x>y时,结合一下模运算的性质不难发现, n n n取 x + y x+y x+y即可
当 x < = y x<=y x<=y时,这种情况就没有那么显然了,需要画个图来表示一下
答案其实很显然了
n m o d x n\;mod\;x nmodx其实就是 p p p与 n n n之间的距离
y m o d n y\; mod \;n ymodn其实就是 n n n与 y y y之间的距离
要使相等,即 n n n为 p p p与 y y y的中点
p y = y m o d x py=y\;mod\;x py=ymodx
故 n n n为 y m o d x 2 \frac{y\;mod\;x}2 2ymodx
考虑简单的贪心
在拆分数字时,我们首先要保证拆成的份数尽量少,再者去保证拆分后的第一个数字尽可能大。我们可以发现第一个条件只会促进第二个条件,即当份数少了,我们就可以让第一个数字更大。
我们设这个数字此时后一位为 k k k,那么它需要变成若干个不大于 k k k的数字,划分次数 d d d即为 ⌈ a i k ⌉ \lceil\frac {a_i}k\rceil ⌈kai⌉
进而算出 k k k的新取值即为 ⌊ a i d ⌋ \lfloor \frac{a_i}d \rfloor ⌊dai⌋
这样,枚举每一个子序列的末尾位置,向前再枚举起始位置,同时统计答案即可,复杂度为 O ( n 2 ) O(n^2) O(n2)
思考一些性质,通过数论分块的思想,每个数拆分后的第一个数字的可能取值和拆分次数近似为 n \sqrt n n个
设 f i f_i fi表示 a i a_i ai此时已经拆成了 f i f_i fi份,从前往后枚举末端位置,再从后往前枚举开始位置,判断新的末端位置对开始位置是否有影响,如果没有,就可以直接break掉,因为从此刻开始对后面也就都没了影响,如果有就更新 f i f_i fi,继续向前更新,由于上述性质,每个数的取值只有 n \sqrt n n个,也就是每个数最多被更新 a i \sqrt {a_i} ai次,很容易就会被 b r e a k break break掉,大大减少时间复杂度,均摊约为 n n n\sqrt n nn
首先考虑朴素 d p dp dp
设 f i , j f_{i,j} fi,j表示前 i i i个数分为 k k k份的最小值
目标: f n , k f_{n,k} fn,k
初值: f 0 , 0 = 0 f_{0,0}=0 f0,0=0,其余均为 I N F INF INF
转移方程: f i , j = m i n k = 0 i − 1 f k , j − 1 + c ( k + 1 , j ) f_{i,j}=min_{k=0}^{i-1}f_{k,j-1}+c(k+1,j) fi,j=mink=0i−1fk,j−1+c(k+1,j)
考虑如何求解 c ( k + 1 , j ) c(k+1,j) c(k+1,j)
为了后面求解方便,式子中的 j ! = i j!=i j!=i,将 j = i j=i j=i的情况特殊计算,当 j = i j=i j=i时,一定满足条件,所以直接加上 r − l + 1 r-l+1 r−l+1
开始推式子:
c ( l , r ) = ∑ i = l r ∑ j = i + 1 r [ g c d ( i , j ) ≥ l ] = ∑ d = l r ∑ i = l r ∑ j = i + 1 r [ g c d ( i , j ) = = d ] = ∑ d = l r ∑ i = ⌈ l d ⌉ ⌊ r d ⌋ ∑ j = i + 1 ⌊ r d ⌋ [ g c d ( i , j ) = = 1 ] = ∑ d = l r ∑ i = 1 ⌊ r d ⌋ ∑ j = i + 1 ⌊ r d ⌋ [ g c d ( i , j ) = = 1 ] = ∑ d = l r ∑ i = 1 ⌊ r d ⌋ ϕ i c(l,r)=\sum_{i=l}^r\sum_{j=i+1}^r[gcd(i,j)\geq l]=\sum_{d=l}^r\sum_{i=l}^r\sum_{j=i+1}^r[gcd(i,j)== d]=\sum_{d=l}^r\sum_{i=\lceil \frac l d\rceil}^{\lfloor \frac r d\rfloor}\sum_{j=i+1}^{\lfloor \frac r d\rfloor}[gcd(i,j)== 1]=\sum_{d=l}^r\sum_{i=1}^{\lfloor \frac r d\rfloor}\sum_{j=i+1}^{\lfloor \frac r d\rfloor}[gcd(i,j)== 1]=\sum_{d=l}^r\sum_{i=1}^{\lfloor \frac r d\rfloor}\phi i c(l,r)=i=l∑rj=i+1∑r[gcd(i,j)≥l]=d=l∑ri=l∑rj=i+1∑r[gcd(i,j)==d]=d=l∑ri=⌈dl⌉∑⌊dr⌋j=i+1∑⌊dr⌋[gcd(i,j)==1]=d=l∑ri=1∑⌊dr⌋j=i+1∑⌊dr⌋[gcd(i,j)==1]=d=l∑ri=1∑⌊dr⌋ϕi
所以我们可以线性求出 ϕ \phi ϕ的前缀和,然后通过整除分块得到 c ( k + 1 , j ) c(k+1,j) c(k+1,j)
此时总复杂度为 O ( T n 3 n ) O(Tn^3\sqrt n) O(Tn3n)
显然超时,考虑优化
没有必要从 1 1 1到 n n n枚举所有 j j j,思考性质,当 K K K大于 20 20 20时,我们可以将区间都划分为形如 [ l , 2 ∗ l − 1 ] [l,2*l-1] [l,2∗l−1]的区间,这样会使 c c c的取值最小化为区间长度,也就可以使答案最小值为 n n n,所以我们只需求出 K ≤ 20 K\leq20 K≤20时的答案,这样总状态数就由 n 2 n^2 n2变为了 20 ∗ n 20*n 20∗n,也就可以存储了,所以我们计算出每种状态的答案, O ( 1 ) O(1) O(1)回答,复杂度降低为
O ( 20 ∗ n 2 n ) O(20*n^2\sqrt n) O(20∗n2n)
依旧不可过,继续优化
转移方程式是很套路的四边形不等式优化,打表易证明 c i , j c_{i,j} ci,j满足四边形不等式条件
所以进行四边形不等式优化 d p dp dp,复杂度将为 20 n l o g n n 20nlogn\sqrt n 20nlognn
可通过此题
一道需要推出来7个性质的题,没有完全搞懂,留坑
跟线性代数和生成函数有关,不会,留坑
水题,暴力插就行了,不多赘述
有点意思但不是很难的题,不要使问题被题目描述复杂化
分两种情况讨论,当 n n n为偶数时,那你把串每一个点单独划分出来,长度都为 1 1 1,由于是偶数,异或起来答案必然为 0 0 0
举一反三,当 n n n为奇数时,你只需要想办法把两个串拼一块使他们的 L I S LIS LIS依然为 1 1 1,找一个 a i > = a i + 1 a_i>=a_{i+1} ai>=ai+1的位置合并即可
容易发现每次操作可以使绝对值内的数字 + 3 , − 3 +3,-3 +3,−3或不变,所以只需要令它对 3 3 3取模,转化为 − 1 , 0 , 1 -1,0,1 −1,0,1即可
把前面的 1 1 1换到后面的 0 0 0即可
判断相邻两个 a a a是否合法即可
或者由于合法的方案数非常有限,可以直接写几个 i f if if来判断
首先转化模型,要使自己赢得点尽可能多,极端情况下,可以使后手第一步就无路可走
即尝试构造出一个图,使一条边连接的两点满足 u ⊕ v > m i n ( u , v ) u⊕v>min(u,v) u⊕v>min(u,v)
考虑如何满足这个性质
当 u u u与 v v v二进制位数不同时,易得 u ⊕ v > m i n ( u , v ) u⊕v>min(u,v) u⊕v>min(u,v)
根据这个性质,问题转化为
构造出一个图,使一条边连接的两点满足二进制位数不同
使用二分图染色来完成如上问题
将图(树)分成两部分(二分图划分),分配数字即可
可证明一定有一种合法的分配方案
数字可根据二进制位数进行分组:
当二进制位数为 1 1 1位时,个数为 1 1 1,即 1 1 1
当二进制位数为 2 2 2位时,个数为 2 2 2,即 2 , 3 , 4 2,3,4 2,3,4
当二进制位数为 3 3 3位时,个数为 4 4 4,即 5 , 6 , 7 , 8 5,6,7,8 5,6,7,8
当二进制位数为 n n n位时,个数为 2 n − 1 2^{n-1} 2n−1
我们怎么判断每一组数字分到图中的哪一部分呢
对其中一部分的大小进行二进制拆分,若它的第 i i i位上是 1 1 1,则将第 i i i组分给这部分,余下的全部分给另一个部分即可
套路转化:
把 a a a变为 b ⟺ b\iff b⟺把 a − b a-b a−b变为 0 0 0
故设 c i = a i − b i c_i=a_i-b_i ci=ai−bi,目的将 c i c_i ci全部变为 0 0 0的最小步数
设 f i f_i fi为 i i i位置的操作次数
可得:(下面式子省略了绝对值符号)
f 1 = c 1 f_1=c_1 f1=c1
f 2 = c 2 − f 1 = c 2 − c 1 f_2=c_2-f_1=c_2-c_1 f2=c2−f1=c2−c1
f 3 = c 3 − f 1 = c 3 − c 1 f_3=c_3-f_1=c_3-c_1 f3=c3−f1=c3−c1
f 4 = c 4 − f 1 − f 2 = c 4 − c 2 f_4=c_4-f_1-f_2=c_4-c_2 f4=c4−f1−f2=c4−c2
f n = ∣ c n − ∑ d ∣ n d ≠ n f d ∣ f_n=|c_n-\sum_{d|n}^{d\ne n}f_d| fn=∣cn−∑d∣nd=nfd∣
实际上
f i = ∣ ∑ d ∣ i μ ( i d ) ∗ c d ∣ f_i=|\sum_{d|i}μ(\frac i d)*c_d| fi=∣d∣i∑μ(di)∗cd∣
至于为什么是莫比乌斯函数,可通过二项式定理+归纳法证明
由于我们未知 b 1 b_1 b1,故未知 c 1 c_1 c1,也就是无法算出 μ ( i ) ∗ c 1 μ(i )*c_1 μ(i)∗c1这一项,由于有绝对值符号的存在,所以我们需要考虑正负时的变号
分类讨论:
当 μ ( i ) = 0 μ(i )=0 μ(i)=0,此项为 0 0 0,答案可以直接统计好
当 μ ( i ) = 1 μ(i )=1 μ(i)=1,可以将满足条件的 i i i对应的 f i f_i fi都存下来,进行排序,然后二分出有多少个数 + c 1 +c_1 +c1 ≥ 0 \ge0 ≥0,对 ≥ 0 \ge0 ≥0的数和 ≤ 0 \le0 ≤0的数分别 O ( 1 ) O(1) O(1)计算答案即可
当 μ ( i ) = − 1 μ(i )=-1 μ(i)=−1,同上
思考性质:
合法序列可以通过一系列操作删至不超过一个数,而不合法序列无法达到此要求,具体操作如下:
1.令 X = 0 X=0 X=0
2.从序列中选择两个数 x , y x,y x,y,满足 x o r X = y o r X x\;or\;X=y\;or\;X xorX=yorX
3.令 X = x o r X X=x\;or\;X X=xorX,从序列中删除 x , y x,y x,y后返回第二步
合法序列满足此要求的原因是:每一步选择的 x , y x,y x,y在之后的步骤中依然可以使用
通过这种操作,也可以从一个不合法序列中,抽取出一个合法序列,这就是解决本题的关键
补集转化一下,求合法序列,即为求总序列数减去不合法序列数
定义 f i . j f_{i.j} fi.j为 i i i个数字,每个数值域为 [ 0 , 2 j ) [0,2^j) [0,2j), i i i个数字按位或为 2 j − 1 2^j-1 2j−1的方案数
进行容斥 d p dp dp:
f i , j = ∑ l = 0 j ( − 1 ) j − l C j l ( 2 l ) i f_{i,j}=\sum_{l=0}^j(-1)^{j-l}C_j^l(2^l)^i fi,j=l=0∑j(−1)j−lCjl(2l)i
l l l表示这 i i i个数中,有相同的 l l l位可以随意选择 0 0 0或 1 1 1,剩下的 j − l j-l j−l位只能选择 0 0 0
则每一项分别为:容斥系数,在 j j j位选择哪 l l l位作为随意选择的位数,以及这 l l l位随意选择的方案
定义 g i , j g_{i,j} gi,j为 i i i个数字,每个数值域为 ( 0 , 2 j ) (0,2^j) (0,2j), i i i个数字按位或为 2 j − 1 2^j-1 2j−1,且 i i i个数字互不相同的方案数
为何如此定义呢?因为当一个不合法序列把它内部最长的好序列删除后,剩下的元素一定不为 0 0 0且均不相同,否则则可以继续加入好序列中
进行容斥 d p dp dp
g i , j = ∑ l = 0 j ( − 1 ) j − l C j l A 2 l − 1 i g_{i,j}=\sum_{l=0}^j(-1)^{j-l}C^l_jA_{2^l-1}^i gi,j=l=0∑j(−1)j−lCjlA2l−1i
思路同上,不过多了两个条件而已,不为 0 0 0对应 2 l − 1 2^l-1 2l−1,不相同对应改为 A A A
定义 h i , j h_{i,j} hi,j为 i i i个数字, i i i个数字按位或为 2 j − 1 2^j-1 2j−1,且 i i i个数字互不相同的不合法方案数
不难发现不合法方案中的最长合法方案的长度一定小于它,二进制中 1 1 1的个数也小于它,所以枚举这个不合法方案中的合法方案
h i , j = ∑ i ′ = 0 i − 1 ∑ j ′ = 0 j − 1 C i i ′ C j j ′ ( 2 j ′ ) i − i ′ g i − i ′ , j − j ′ ( f i ′ , j ′ − h i ′ , j ′ ) h_{i,j}=\sum_{i'=0}^{i-1}\sum_{j'=0}^{j-1}C_i^{i'}C_j^{j'}(2^{j'})^{i-i'}g_{i-i',j-j'}(f_{i',j'}-h_{i',j'}) hi,j=i′=0∑i−1j′=0∑j−1Cii′Cjj′(2j′)i−i′gi−i′,j−j′(fi′,j′−hi′,j′)
每一项分别为:选择哪 i ′ i' i′个数作为最长合法序列;选择哪 j ′ j' j′位作为合法序列中的 1 1 1的位置;删去最长合法序列后的不合法序列中的 j ′ j' j′个位置上都可以随意放置 0 0 0或 1 1 1,无论选什么都不会影响结果;删去最长合法序列后的不合法序列需要满足不为 0 0 0且两两互不相同,即为之前求出的 g g g数组;最长合法序列的方案数(总序列数-不合法序列数)
补集转化求得答案即可
注意一些小细节:
空串是一个好序列,因为若有一个坏序列中无法抽出好序列,那么它的最长好序列就应该是一个空串
一个偶数好序列,在其中间加入任何数字,它仍然是一个好序列,但我们在统计过程中,不把它当做好序列,因为一个好序列需要同时拿出 x , y x,y x,y,一定有偶数个元素,所以只需要在最后统计 n n n的答案时,将奇数的情况特殊考虑一下即可
考虑将序列按照下标顺序排为两行
例如样例中的: a a b b b a b a a aabbbabaa aabbbabaa
排列为:
a a a a a aa\;\;\;\;\;a\;\;aa aaaaa
b b b b \;\;\;\;bbb\;\;b\;\; bbbb
那么 a b ab ab出现次数即为从上一行走到下一行的次数
同理 b a ba ba出现次数即为从下一行走到上一行的次数
那么只要最开头的元素和最后一个元素相同,那么上下波动次数就会相同,根据这个性质修改字符串即可
容易得到传递速度是二的幂,传递速度的上限为 k k k,根据此性质推个数学式即可
第 i i i种只能选 1 0 a i + 1 − a i − 1 10^{a_i+1-a_i}-1 10ai+1−ai−1个,如果多选则可以用 i + 1 i+1 i+1张替代,第 n n n张可以无限选,所以贪心的把面值较小的选完即可
暴力枚举每行染什么颜色,显然复杂度太高了,考虑能不能减少这一步复杂度
由于我们必须保证第一列的数,红色元素比所有蓝色元素大,所以可以按照第一行的大小顺序,将整个序列重新排序,这样的话就可以枚举红蓝两色的分割线,只需要 O ( n ) O(n) O(n)的复杂度
那么还需要枚举 k k k的位置,这样总复杂度 O ( n m ) O(nm) O(nm),目前可过,最后一步即为怎么判断这四部分矩阵是否完全合法呢?
左矩阵中所有红色元素比所有蓝色元素大
可以转化为
左矩阵中红色元素的最小值比蓝色元素的最大值大
另一个条件也同理转化
那么最小值和最大值可以通过前缀和预处理求出,只需要从4个角做四遍前缀和即可
计数 d p dp dp
设 f i , j f_{i,j} fi,j表示还存活个 i i i个角色,这 i i i个角色的最大血量为 j j j的方案数
两种情况讨论:
当 j ≤ i − 1 j\leq i-1 j≤i−1,那么这一回合所有人都会死,也就满足条件,这种情况下,可以直接计数
f i , j = j i − ( j − 1 ) i f_{i,j}=j^i-(j-1)^i fi,j=ji−(j−1)i
也就是 i i i个人的血量都在 1 — j 1—j 1—j的范围内,再减去 i i i个人的血量都在 1 — j − 1 1—j-1 1—j−1的范围内的非法方案
当 j > i − 1 j>i-1 j>i−1时
这一轮会把最大血量的人的血量刷到 j − ( i − 1 ) j-(i-1) j−(i−1)
我们再去枚举这一轮后还有多少个人活着
设还有 k k k个人活着,那么 i i i个人中选择 k k k个作为活着的人的方案为 C i k C_i^k Cik
那么剩下被击杀的 i − k i-k i−k个人,他们的血量可以控制在 1 — i − 1 1—i-1 1—i−1中的任意一个数
故可得:
f i , j = ∑ k = 1 i f k , j − ( i − 1 ) × C i k × ( i − 1 ) i − k f_{i,j}=\sum _{k=1}^if_{k,j-(i-1)} \times C_i^k\times (i-1)^{i-k} fi,j=∑k=1ifk,j−(i−1)×Cik×(i−1)i−k
故最后答案为 ∑ i = 1 x f n , i \sum_{i=1}^x f_{n,i} ∑i=1xfn,i
根号分治好题
一个节点都不删,那么 a n s ans ans肯定是 ≥ 0 \ge 0 ≥0的
以此为基础,我么可以推出一些有趣的性质:
a n s ≥ 0 ans\ge 0 ans≥0
c ( v ) − m k ≥ 0 c(v)-mk\ge 0 c(v)−mk≥0
m k ≤ c ( v ) ≤ n mk\le c(v)\le n mk≤c(v)≤n
m ≤ n k m\le \frac n k m≤kn
这样一个式子就可以引发出我们根号分治的想法
将问题转化为两部分:
当 k < n k<\sqrt n k<n时
由于 k k k的范围很小,我们可以对每个 k k k,都求出答案,对于每个 k k k都进行一遍树形 d p dp dp,求出每个节点的最优值
具体如下:
对于每个 k k k
设 f i f_{i} fi表示 i i i的最优答案
那么对于 i i i的子节点 j j j,可以选择不删它,把它加到 i i i上,那么价值为 f i + 1 f_i+1 fi+1,也可以选择删它,把它的最优子节点加到 i i i上,那么价值为 f i + f j − k f_i+f_j-k fi+fj−k,取 m a x max max即可
当 k ≥ n k\ge \sqrt n k≥n时
由于 m ≤ n k m\le \frac n k m≤kn
所以 m ≤ n m\le \sqrt n m≤n
也就是删的节点数不超过 n \sqrt n n个,那么就可以设计另一个 d p dp dp
设 g i , j g_{i,j} gi,j表示 i i i的子树内,删除了 j j j个节点的最优价值
那么枚举每个子节点的子树内,删了 d d d个节点,比照上一个树形 d p dp dp,进行另一个树形 d p dp dp即可
注意上述两个 d p dp dp,我们都需要开一个二维数组,那么一个 n n n\sqrt n nn的数组空间复杂度就已经达到300+MB,两个就会爆掉空间,所以必须同时用一个来进行 d p dp dp,那也就要求了询问必须完全离线出来,先做完第一种情况,求出所有答案后,再重复利用数组,进行第二个 d p dp dp