给定一个 n n n 个节点的有根树,每个节点有一个权值 A i A_i Ai。定义一个集合的价值为: V a l u e ( S ) = ∑ x ∈ S ∑ y ∈ S ( A x ⊕ A y ) 2 Value(S)=\sum_{x\in S}\sum_{y \in S}{(A_x \oplus A_y)^2} Value(S)=x∈S∑y∈S∑(Ax⊕Ay)2
求以每个节点 x x x 为根的子树中距离 x x x 不超过 k k k 的节点集合 V ( x , k ) V(x,k) V(x,k) 的价值。
k ≤ n ≤ 1 0 5 , 0 ≤ A i ≤ 1 0 9 k \leq n \leq 10^5,0 \leq A_i \leq 10^9 k≤n≤105,0≤Ai≤109
考虑如何计算一个集合的价值,问题的难点在于求 ∑ ( a ⊕ b ) 2 \sum_{(a \oplus b)^2} ∑(a⊕b)2,设 a ⊕ b = x a \oplus b = x a⊕b=x 并写出 x x x 的二进制表示 x = x 30 + x 29 + . . . + x 0 x = x_{30}+ x_{29} + ... + x_0 x=x30+x29+...+x0。
则 x 2 = ( ∑ x i ) 2 = ∑ ∑ x i x j x^2=(\sum{x_i})^2=\sum\sum{x_i x_j} x2=(∑xi)2=∑∑xixj,这提示我们对于每两位 ( i , j ) (i,j) (i,j) 计算出有多少对 ( a , b ) (a,b) (a,b) 满足 a ⊕ b a \oplus b a⊕b 的第 i i i 位和第 j j j 位均为 1 1 1 即可。
这一步的计算可以通过维护有多少个数满足第 i i i 位为 x i x_i xi ,第 j j j 位为 x j x_j xj,设为 s ( x i , x j ) s(x_i,x_j) s(xi,xj)。然后用 s ( 0 , 0 ) s ( 1 , 1 ) + s ( 0 , 1 ) s ( 1 , 0 ) s(0,0)s(1,1)+s(0,1)s(1,0) s(0,0)s(1,1)+s(0,1)s(1,0) 就能计算出对答案的贡献。
现在我们将这种做法推广到原问题,使用长链剖分维护每个深度的信息,前缀和计算即可。
设权值的字长为 w w w ,则总时间复杂度为 O ( n w 2 ) O(nw^2) O(nw2),空间复杂度为 O ( n ) O(n) O(n)。
给出 n ( n ≤ 100000 ) n(n\leq100000) n(n≤100000)个物品,每个物品有一个 n a m e name name属性和一个 c o l o r color color属性和一个 p o w e r power power,再给出 5 5 5个 n a m e name name值和 1 1 1个 c o l o r color color值。选出 5 5 5个物品,定义 b o n u s bonus bonus初始为 1 1 1,每有一个物品的 n a m e name name在给出的 n a m e name name中则 b o n u s + = 10 % bonus+=10\% bonus+=10%,每有一个物品的 c o l o r color color为给出的 c o l o r color color则 b o n u s + = 20 % bonus+=20\% bonus+=20%,定义 得 分 = 5 个 物 品 p o w e r 的 和 × b o n u s 得分=5个物品power的和\times bonus 得分=5个物品power的和×bonus,求选出的 5 5 5个物品得分最高为多少
所有的牌都可以分为4类
0:名字没有加成,颜色没有加成
1:名字有加成,颜色没有加成
2:名字没有加成,颜色有加成
3:名字有加成,颜色有加成
把类别相同的都放在同一个数组中
然后把每个数组都按照power从大到小排序。
题目要求每个名字只能被选取一次,因此对每个数组去重,每个名字只保留power最高的。
设最后的四个数组为V[0],V[1],V[2],V[3]
然后进行搜索,深度为5
每次从V[0],V[1],V[2],V[3]中选取一张牌。
每次选取时都优先选power最高的,如果名字重复就跳过
dfs部分大概长这样
void dfs(int deep,int nname,int ncolor,int power,int i0,int i1,int i2,int i3,set<string>name_set){
if(deep == 0){
update(ans,power*(1.0+nname*0.1+ncolor*0.2));
return;
}
//V[0]部分
...//跳过名字相同的,因为name_set最多5个元素,因此复杂度很低
name_set.insert(now_name);
dfs(deep-1,nname,ncolor,power+now_power,i0+1,i1,i2,i3,name_set);
name_set.erase(now_name);
//V[1]部分
...//同样跳过
name_set.insert(now_name);
dfs(deep-1,nname+1,ncolor,power+now_power,i0,i1+1,i2,i3,name_set);
name_set.erase(now_name);
//后面都差不多
}
时间复杂度:
排序 O ( n l o g n ) O(nlogn) O(nlogn)
搜索 O ( 1 ) O(1) O(1)
因此总复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)
输出 1 1 2 3 5
。
一个 n × m n\times m n×m 矩阵, n , m ≥ 2 n,m\geq 2 n,m≥2 ,初始全0,每次可以行+1或列+1。现在某一个数丢失,求它是多少。
注意到 a x y + a z w = a x w + a z y a_{xy}+a_{zw}=a_{xw}+a_{zy} axy+azw=axw+azy 即可。
维护一个数组,区间乘一个 2 ≤ x ≤ 10 2\leq x\leq 10 2≤x≤10 的数字,区间查询 pot ( x ) \operatorname{pot}(x) pot(x) 的最大值,其中
pot ( x ) : = max p p r i m e , p c ∣ x c . \operatorname{pot}(x):=\max_{p\ \mathrm{prime},\ p^c|x}c. pot(x):=p prime, pc∣xmaxc.
做法:对 2 , 3 , 5 , 7 2,3,5,7 2,3,5,7 分别维护一颗线段树,区间加、区间取 max \max max 即可。
求
∑ a = 2 n a ∑ b = a n ⌊ log a b ⌋ ⌈ log b a ⌉ , n ≤ 1 0 12 . \sum_{a=2}^n a\sum_{b=a}^n{\left\lfloor\log_a b\right\rfloor\left\lceil\log_b a\right\rceil},\,n\leq10^{12}. a=2∑nab=a∑n⌊logab⌋⌈logba⌉,n≤1012.
注意到 b ≥ a b\geq a b≥a 时 ⌈ log b a ⌉ = 1 \lceil \log_b a\rceil=1 ⌈logba⌉=1 。 a ≤ n a \leq \sqrt n a≤n 可枚举内层爆算, a > n a>\sqrt n a>n 时内层的乘积就是 1 1 1 ,因此内层 ∑ = n − a + 1 \sum=n-a+1 ∑=n−a+1 。
将一个 x x x 进制下的数字 k k k 转换到 y y y 进制下。 k ≤ x 120 k\leq x^{120} k≤x120 。
简单 Python 作业题。注意特判 0。
给定两个 n × m n\times m n×m 矩阵,每个里面元素都是 1 … n × m 1\dots n\times m 1…n×m 且两两不同。求最大公共(连续)子矩阵大小。
做法:因为是排列所以可以找到每个元素在哪里。 O ( n m ) O(nm) O(nm) 可以求出每个 a i j a_{ij} aij 在 b b b 里面向上、左、右走 1 × k 1\times k 1×k 或 k × 1 k\times 1 k×1 能走多远,分别设为 U ( i , j ) , L ( i , j ) , R ( i , j ) U(i,j),\,L(i,j),\,R(i,j) U(i,j),L(i,j),R(i,j)。剩下的事情是一个悬线法:
就做完了。
我们定义一个序列 a 1 , ⋯ , a n a_1,\cdots,a_n a1,⋯,an 是 ( n , m , d ) (n,m,d) (n,m,d)-好的,当且仅当:
给定 n , m , d , k n,m,d,k n,m,d,k ,求所有 ( n , m , d ) (n,m,d) (n,m,d)-好的序列的“所有元素的积的 k k k 次幂”的和,对某个合数取模。输入的 n ≤ 1 0 100000 , m ≤ 100000 , k ≤ 1 0 9 n\leq 10^{100000},\,m\leq 100000,\,k\leq 10^9 n≤10100000,m≤100000,k≤109 。
下述过程中, n n n 只出现在指数位置上,所以我们只需要取 n ← n m o d φ ( m o d ) n\leftarrow n\bmod \varphi(mod) n←nmodφ(mod) ,这样的读入是轻易的。给定 n , k n,k n,k ,我们设 f ( x ) f(x) f(x) 是所有 ( n , x , 1 ) (n,x,1) (n,x,1)-好的序列的“所有元素的积的 k k k 次幂”的和。则答案是 d k n f ( ⌊ m d ⌋ ) d^{kn} f\left(\left\lfloor\frac{m}{d}\right\rfloor\right) dknf(⌊dm⌋) 。注意到我们有容斥
f ( x ) = ( T x ) n − ∑ j = 2 x j k n f ( ⌊ x j ⌋ ) , f(x)=(T_x)^n-\sum_{j=2}^x j^{kn}f\left(\left\lfloor\frac{x}{j}\right\rfloor\right), f(x)=(Tx)n−j=2∑xjknf(⌊jx⌋),
其中 T x = ∑ i = 1 x i k T_x=\sum_{i=1}^x i^k Tx=∑i=1xik 。第一项是不考虑 gcd \gcd gcd 限制的总和,后面的是 gcd \gcd gcd 容斥。记忆化搜索,所有的状态都形如 f ( ⌊ m j ⌋ ) f\left(\left\lfloor\frac{m}{j}\right\rfloor\right) f(⌊jm⌋) for some j j j ,故状态只有 O ( m ) O\left(\sqrt m\right) O(m) 个。
考虑转移,这是简单的数论分块:若 j ≤ x j\leq \sqrt x j≤x 直接算;若 j > x j>\sqrt x j>x ,枚举 p = ⌊ x j ⌋ < x p=\left\lfloor\frac{x}{j}\right\rfloor< \sqrt x p=⌊jx⌋<x ,考虑满足 ⌊ x j ⌋ = p \left\lfloor\frac{x}{j}\right\rfloor =p ⌊jx⌋=p 的 j j j 是一个区间 [ ⌊ x / ( p + 1 ) ⌋ + 1 , ⌊ x / p ⌋ ] [\lfloor x/(p+1)\rfloor+1,\lfloor x/p\rfloor] [⌊x/(p+1)⌋+1,⌊x/p⌋] ,对这个区间计算贡献,只要预处理 j k n j^{kn} jkn 的前缀和然后减一减就可以了。因此转移复杂度 O ( m ) O(\sqrt m) O(m) ,故DP的总复杂度 O ( m ) O(m) O(m) 。
再来看预处理的复杂度。预处理要求 i k i^k ik 的前缀和与 i k n i^{kn} ikn 的前缀和。先求出他们俩本身:这两个东西都是完全积性函数,可以 O ( m log m log m o d ) O\left(\frac{m}{\log{m}}\log mod\right) O(logmmlogmod) 线性筛,因此可以线性求出;然后前缀和也是线性的。因此总复杂度是 O ( m ) O(m) O(m) 的。
给你一张每条边至多在一个简单环上的无向图,边有非负边权。求:从1号节点出发,经过每条边至少一次,结束在任意位置的最短方案。要求复杂度线性。
首先,一些基本的常识和术语可见vfk的玩转仙人掌讲义。需要前置完成构建仙人掌的 Block Forest 结构(又名“仙人掌的圆方树”、点双树,就是vfk讲义里面没有提到名字的树结构,把环上的点作为环儿子,把环的最高顶点作为环父亲)。额外地,需要维护环上边权的前缀和。这些都可以朴素完成。
我们定义 F x F_x Fx 为从 x x x 的父亲进入 x x x 的子仙人掌,遍历所有边至少一遍,然后回到 x x x 的父亲的最小花费;定义 G x G_x Gx 为从 x x x 的父亲进入 x x x 的子仙人掌,遍历所有边至少一次,最后停止在任意节点的最小花费。注意如果 x x x 不是环, F x , G x F_x,G_x Fx,Gx 中就会包含 ( f a t h e r x , x ) (\mathrm{father}_x,x) (fatherx,x) 的边权(两次或一次,resp.)。我们可以给根定义一个零花费的父向边以避免一些无谓的平凡情况。以下的 DP 过程几乎是平凡的,但在此详述,只为搞清一下细节。
若 x x x 是结点(“圆点”),那么 F x = 2 w ( ( f a t h e r x , x ) ) + ∑ y ∈ s o n s x F y F_x=2w((\mathrm{father}_x,x))+\sum\limits_{y\in\mathrm{sons}_x} F_y Fx=2w((fatherx,x))+y∈sonsx∑Fy ,其中 e ↦ w ( e ) e\mapsto w(e) e↦w(e) 代表边权;若 x x x 是环(“方点”),可以发现最优方案是环边只走一遍、所有其他孩子直接进去再回来,因此 F x = ∑ e ∈ e d g e s x w ( e ) + ∑ y ∈ s o n s x F y F_x=\sum\limits_{e\in \mathrm{edges}_x} w(e)+\sum\limits_{y\in\mathrm{sons}_x} F_y Fx=e∈edgesx∑w(e)+y∈sonsx∑Fy 。
若 x x x 是结点,考虑 G x G_x Gx ,进入 x x x 之后,最后一定会落在某个子仙人掌中,因此枚举最后终结的地方在哪个孩子的子树中,可以得到
G x = w ( ( f a t h e r x , x ) ) + min y ∈ s o n s x ( G y + ∑ z ∈ s o n s x , z ≠ y F y ) = F x − w ( ( f a t h e r x , x ) ) + min y ∈ s o n s x ( G y − F y ) , \begin{aligned}G_x &=w((\mathrm{father}_x,x))+\min\limits_{y\in\mathrm{sons}_x} \left(G_y+\sum\limits_{z\in\mathrm{sons}_x,\,z\neq y} F_y\right)\\&=F_x-w((\mathrm{father}_x,x))+\min\limits_{y\in\mathrm{sons}_x}\left(G_y-F_y\right),\end{aligned} Gx=w((fatherx,x))+y∈sonsxmin⎝⎛Gy+z∈sonsx,z=y∑Fy⎠⎞=Fx−w((fatherx,x))+y∈sonsxmin(Gy−Fy),
若 x x x 是环,可以发现总会落在某一个节点的子仙人掌中,照样枚举是哪个节点。假设它是 y y y 。由于环上的每条边都要经过一遍,我们从顶点开始、先走一圈、回到顶点,然后从顶点下到 y y y 。
G x = ∑ e ∈ e d g e s x w ( e ) + min y ∈ s o n s x ( d i s ( x , y ) + G y + ∑ z ∈ s o n s x , z ≠ y F y ) = F x + min ( 0 , min y ∈ s o n s x ( d i s ( x , y ) + G y − F y ) ) , \begin{aligned}G_x &=\sum\limits_{e\in \mathrm{edges}_x} w(e)+\min\limits_{y\in\mathrm{sons}_x} \left(\mathrm{dis}(x,y)+G_y+\sum\limits_{z\in\mathrm{sons}_x,\,z\neq y} F_y\right)\\&=F_x+\min\left(0,\min\limits_{y\in\mathrm{sons}_x}\left(\mathrm{dis}(x,y)+G_y-F_y\right)\right),\end{aligned} Gx=e∈edgesx∑w(e)+y∈sonsxmin⎝⎛dis(x,y)+Gy+z∈sonsx,z=y∑Fy⎠⎞=Fx+min(0,y∈sonsxmin(dis(x,y)+Gy−Fy)),
其中 d i s \mathrm{dis} dis 由于在同一个环上,可以把环的两侧取 min \min min ,这里要用到上述的“环上的边权前缀和”。
答案就是 G 1 G_1 G1 了。