题意
有一串糖果箱,每个箱子有颜色,装有一定数量的糖果,然后现在要用大一点的条状箱子把它们运回去,每个条状箱子中装的是一段连续的箱子,不能有相同颜色的箱子,每个箱子的运费是所有箱子糖果数的按位或的和。求最小运费。
1
≤
1\leq
1≤箱子数量
≤
5
∗
1
0
5
\leq5*10^5
≤5∗105
1
≤
1\leq
1≤颜色
≤
1
0
6
\leq10^6
≤106
0
≤
0\leq
0≤糖果数
≤
1
0
6
\leq10^6
≤106
传送
题解
令
d
p
[
i
]
dp[i]
dp[i]表示前i个箱子装完的最小代价,令
l
m
a
x
[
i
]
l_{max}[i]
lmax[i]表示最左边的一个位置,使得这个位置到
i
i
i都没有重复的颜色。那么有一个比较显然的dp方程
d
p
[
i
]
=
m
i
n
d
p
[
j
−
1
]
+
o
r
(
i
,
j
)
(
l
m
a
x
[
i
]
≤
j
≤
i
−
1
)
dp[i]=min \ dp[j-1]+or(i,j) \ \ \ \ \ \ (l_{max}[i]\leq j\leq i-1)
dp[i]=min dp[j−1]+or(i,j) (lmax[i]≤j≤i−1)
o
r
(
i
,
j
)
=
a
i
o
r
a
i
+
1
o
r
⋅
⋅
⋅
o
r
a
j
or(i,j)=a_i \ or\ a_{i+1}\ or\ ···\ or\ a_j
or(i,j)=ai or ai+1 or ⋅⋅⋅ or aj
然后显然时间复杂度是
O
(
n
2
)
O(n^2)
O(n2)的,考虑优化。
方法一
区间 m i n min min,上线段树。
然后就是从左往右遍历的时候这个 o r or or函数非常不好搞,按位拆开的话,总和的 m i n min min又不好求,但是我们发现我们始终维护的是一些右端点为 i i i的区间,这意味着,如果在 i i i之前有一个 a j a_j aj的第 b b b个二进制位是 1 1 1,那么 o r ( 1 , i ) , o r ( 2 , i ) , ⋅ ⋅ ⋅ , o r ( j , i ) or(1,i),or(2,i),···,or(j,i) or(1,i),or(2,i),⋅⋅⋅,or(j,i)的第b个二进制位都是1,所以我们枚举当前糖果数量 V i V_i Vi的是1的二进制位,预处理 p r e [ i ] [ j ] pre[i][j] pre[i][j]表示i位置前最近的,第j个二进制位是1的数的位置,这个数组 O ( n log V i ) O(n\log V_i) O(nlogVi)就可以处理完毕。然后我们就在线段树上的 [ p r e [ i ] [ b ] , i ] [pre[i][b],i] [pre[i][b],i]这个区间加上 2 b 2^b 2b,就可以实现维护。剩下的就很简单了,区间修改,区间查询最小值。时间复杂度 O ( n log n log V i ) O(n\log n\log V_i) O(nlognlogVi)
方法二
同样聚焦于这个or函数,因为or只有区间合并性,没有区间可减性,所以不能用前缀和,用st表 O ( n log n ) O(n\log n) O(nlogn)预处理之后可以做到 O ( 1 ) O(1) O(1)计算 o r ( i , j ) or(i,j) or(i,j)。其次,考虑那一长串的or值 o r ( 1 , i ) , o r ( 2 , i ) , ⋅ ⋅ ⋅ or(1,i),or(2,i),··· or(1,i),or(2,i),⋅⋅⋅其实不同的or值最多只有 O ( log V i ) O(\log V_i) O(logVi)种,而如果 [ a , b ] [a,b] [a,b]这段区间的or值相同,那么我肯定取a转移是更优的。所以我做这么多次二分,找出那 log V i \log V_i logVi个可转移的点,然后转移就行了。时间复杂度也是 O ( n log n log V i ) O(n\log n\log V_i) O(nlognlogVi)