青大蒟蒻第一次在正式的 d i v 2 div2 div2中 A c Ac Ac了五道题,也是小蒟蒻有史以来发挥最好的一场,这场过后我的cf也许可能也要变成黄了。
A. Flip Flop Sum
题意:给定一个
a
——
i
a——i
a——i数组,权值仅为1或-1,我们选择相邻两位并翻转(1变-1,-1变1),能够得到的最大和是多少,
n
<
=
2
e
5
n <= 2e5
n<=2e5。
思路:暴力枚举所有的相邻位并翻转找最大和即可。
代码
B. The Forbidden Permutation
题意:给定一个长度为
n
n
n排列数组
p
p
p , 给你长度为
m
m
m且元素互不相同的数组
a
a
a,一个数组是坏的当且仅当所有的
1
<
=
i
<
m
1 <= i < m
1<=i<m满足
p
o
s
(
a
i
)
<
p
o
s
(
a
(
i
+
1
)
)
<
p
o
s
(
a
i
)
+
d
pos(a_i) < pos(a_(i_+1_)) < pos(a_i) + d
pos(ai)<pos(a(i+1))<pos(ai)+d,
p
o
s
(
x
)
pos(x)
pos(x)表示
x
x
x值在
a
a
a数组的位置,现可以执行以下操作,我们可以交换
p
p
p数组的相邻项,求执行多少次操作我们可以让
a
a
a数组是好的,
n
<
=
2
e
5
,
m
<
=
2
e
5
,
a
i
<
=
n
n <= 2e5 , m <= 2e5 ,a_i <= n
n<=2e5,m<=2e5,ai<=n 。
思路 只要破坏坏数组的条件即可,我们发现他要求的是所有的相邻位置都要满足,我们考虑有一个不满足的最小代价即可,分两种情况考虑,考虑
a
(
i
+
1
)
a(i+1)
a(i+1)移动到
a
(
i
)
a(i)
a(i)前面或者
a
(
i
+
1
)
a(i+1)
a(i+1)移动到
a
(
i
)
+
d
a(i) + d
a(i)+d后面,代价去最小值即可。
代码
C. Flexible String
题意:给你两个长度为
n
n
n的字符串
a
a
a 、
b
b
b,我们把价值定义为
(
l
,
r
)
(l , r)
(l,r)对满足要求的个数
(
l
<
=
r
,
l
>
=
1
,
r
<
=
n
)
(l <= r , l >= 1 , r <= n)
(l<=r,l>=1,r<=n),满足要求当且仅当
a
(
l
,
r
)
=
=
b
(
l
,
r
)
a(l , r) == b(l , r)
a(l,r)==b(l,r)a字符串的l到r的子串和b字符串的l到r的子串相同。
我们定义一个
Q
Q
Q堆,我们可以执行以下操作,我们可以将
a
a
a字符串的
a
i
a_i
ai放到
Q
Q
Q堆里,然后将
a
i
a_i
ai替换成任意字符
c
c
c,
Q
Q
Q堆中不同的字符串不能超过
k
k
k种,求字符串经过若干次操作后的最大价值,题目保证字符串
a
a
a、
b
b
b出现的字符串种类不超过10,
k
<
=
10
,
n
<
=
2
e
5
k <= 10 , n <= 2e5
k<=10,n<=2e5。
思路:考虑对10进行二进制枚举,枚举所有的合法状态,求出对应状态的字符串的最大价值即可。时间复杂度
O
(
2
k
∗
n
)
O(2 ^k * n)
O(2k∗n)
代码
D. Flexible String Revisit
题意:给你两个长度为
n
n
n的二进制字符串
a
a
a 、
b
b
b,字符串的取值只有
0
、
1
0、1
0、1 , 我们每一次操作可以随机选择一个下标
i
i
i,然后把
a
i
ai
ai取反
(
0
变
1
,
1
变
0
)
(0 变 1 , 1 变 0)
(0变1,1变0),问把这两个字符串变相同所需的操作期望次数。
思路:考虑转化一下问题,把问题变成
a
i
ai
ai和
b
i
bi
bi相同的个数为
k
k
k,不相同的个数可以推得为
n
−
k
n-k
n−k。
然后我们把
a
i
ai
ai和
b
i
bi
bi相同的个数为
k
k
k称为状态
k
k
k,我们考虑由状态
k
k
k到状态
n
n
n的期望操作
d
p
[
k
]
dp[k]
dp[k]次。
1.操作一次,我们选择了
a
i
ai
ai和
b
i
bi
bi相同里面的下标,由于之前是相同的,取反后变为不相同的,那么状态转移到了状态
k
−
1
k-1
k−1。
2.操作一次,我们选择了
a
i
ai
ai和
b
i
bi
bi不相同里面的下标,由于取反所以不相同的下标变为了相同的下标,转移到了状态
k
+
1
k+1
k+1。
可以推出式子为:
d
p
[
k
]
=
1
+
k
/
n
∗
d
p
[
k
−
1
]
+
(
n
−
k
)
/
n
∗
d
p
[
k
+
1
]
dp[k] = 1 + k/n * dp[k - 1] + (n-k)/n * dp[k+1]
dp[k]=1+k/n∗dp[k−1]+(n−k)/n∗dp[k+1]
观察一下这个式子,我们发现式子中出线了
d
p
[
k
−
1
]
和
d
p
[
k
+
1
]
dp[k - 1] 和 dp[k + 1]
dp[k−1]和dp[k+1],这样的式子是没法求出答案的。
我们考虑转化角度,我们考虑从状态
k
k
k到状态
k
+
1
k + 1
k+1所需的期望操作
d
p
[
k
]
dp[k]
dp[k]次,答案就为
d
p
[
k
]
dp[k]
dp[k]从
m
m
m到
n
−
1
n-1
n−1的和,原因是
m
m
m变到
n
n
n,我们先花费
d
p
[
m
]
dp[m]
dp[m]变成
m
+
1
m+1
m+1,再花费
d
p
[
m
+
1
]
dp[m+1]
dp[m+1]变成
m
+
2
m+2
m+2…以此类推花费
d
p
[
n
−
1
]
dp[n-1]
dp[n−1]变到
n
n
n。
考虑状态转移。
1.操作一次,我们选择了
a
i
ai
ai和
b
i
bi
bi不相同里面的下标,由于取反所以不相同的下标变为了相同的下标,转移到了状态
k
+
1
k+1
k+1,操作次数为1。
2…操作一次,我们选择了
a
i
ai
ai和
b
i
bi
bi相同里面的下标,由于之前是相同的,取反后变为不相同的,那么状态转移到了状态
k
−
1
k-1
k−1,我们从状态
k
−
1
k-1
k−1变到
k
+
1
k+1
k+1需要经历
d
p
[
k
−
1
]
dp[k-1]
dp[k−1]次操作变成状态
k
k
k,再经历
d
p
[
k
]
dp[k]
dp[k]次操作变成状态
k
+
1
k+1
k+1,操作次数为
1
+
d
p
[
k
−
1
]
+
d
p
[
k
]
1 + dp[k - 1] + dp[k]
1+dp[k−1]+dp[k]。
式子就变为:
d
p
[
k
]
=
(
n
−
k
)
/
n
+
k
/
n
∗
(
1
+
d
p
[
k
−
1
]
+
d
p
[
k
]
)
dp[k] = (n - k)/n + k/n * (1 + dp[k - 1] + dp[k])
dp[k]=(n−k)/n+k/n∗(1+dp[k−1]+dp[k])
考虑化简,化简过程如下:
最后式子变为
d
p
[
k
]
=
n
/
(
n
−
k
)
+
k
/
(
n
−
k
)
∗
d
p
[
k
−
1
]
dp[k] = n / (n - k) + k / (n - k) * dp[k - 1]
dp[k]=n/(n−k)+k/(n−k)∗dp[k−1]
转移这个式子即可,初始值
d
p
[
0
]
=
1
dp[0]=1
dp[0]=1,因为由0转移到1一定是一次,因为相同的为空,只能从不相同的选,然后求
m
−
(
n
−
1
)
m - (n -1)
m−(n−1)的
d
p
[
k
]
dp[k]
dp[k]和即可。
代码
E. The Tree Has Fallen!
题意:给你一棵大小为
n
n
n的树,每个点有权值
a
i
ai
ai,有
q
q
q次询问,每次询问问以
r
r
r为根,在
u
u
u子树中选若干个点使得这些点的权值异或和最大,输出这个最大异或和。
思路:考虑离线,我们把询问都变成问
r
r
r为根,
u
u
u子树的最大异或和的形式,然后我们两遍
d
f
s
dfs
dfs,第一遍
d
f
s
dfs
dfs维护以1为根的
s
z
[
u
]
sz[u]
sz[u]的最大异或和(线性基),第二遍
d
f
s
dfs
dfs类似换根
d
p
dp
dp的思路维护以
u
u
u为根的其他节点子树的最大异或和(线性基) ,然后离线地处理所有询问。
原理:两个子树为根的所有维护的子树信息,唯一不同的地方是两个子树之间的路径信息(有根树的方向不一样),然后我们可以考虑先维护1子树的信息,然后用
d
f
s
dfs
dfs特性(可以维护路过的路径信息)去解决问题即可。
往后会更新原理的图文方便理解,线性基合并是基本内容,暂且不在这里细讲。
代码