本文遵循 CC BY-NC-ND 4.0 协议,作者:U•ェ•*U,转载请获得作者授权。
先求 k = 0 k=0 k=0 时的逆序数:用树状数组在 O ( N log M ) O(N\log M) O(NlogM) 时间内统计标准逆序数。
分析
k
→
k
+
1
k\to k+1
k→k+1 时逆序数的变化: 观察每个位置
i
i
i ,当
k
k
k 增加
1
1
1 时,
B
i
=
(
A
i
+
k
)
m
o
d
M
B_i = (A_i+k)\mod M
Bi=(Ai+k)modM 只有在等于模数(即
A
i
+
k
=
M
−
1
A_i+k = M-1
Ai+k=M−1)时变为
0
0
0,就改变了它在序列中的相对大小。可以证明,当某个位置
i
i
i 满足
k
=
M
−
1
−
A
i
k = M-1-A_i
k=M−1−Ai 时,该位置会改变贡献,对全局逆序数的影响为
(
在该位置前的个数
)
−
(
在该位置后的个数
)
=
2
⋅
i
−
(
N
−
1
)
( \text{在该位置前的个数} ) - ( \text{在该位置后的个数} ) = 2\cdot i - (N-1)
(在该位置前的个数)−(在该位置后的个数)=2⋅i−(N−1)
因此可以令一个差分数组
d
i
f
f
diff
diff(下标范围
[
0
,
M
−
1
]
[0,M-1]
[0,M−1])满足:对于每个位置
i
i
i,在
k
=
M
−
1
−
A
i
k = M-1-A_i
k=M−1−Ai 时,加上 $2\cdot i-(N-1) $。
最后,对于每个 k k k,我们加上 d i f f k diff_k diffk 即可。
import sys
n, m = map(int, sys.stdin.readline().split())
a = list(map(int, sys.stdin.readline().split()))
tree = [0] * (200010)
diff = [0] * (200010)
def add(x, val):
x += 1
while x <= m:
tree[x] += val
x += (x & -x)
def query(x):
x += 1
res = 0
while x:
res += tree[x]
x -= (x & -x)
return res
def main():
tmp = 0
for i in range(n):
tmp += i - query(a[i])
add(a[i], 1)
diff[m - 1 - a[i]] += (2 * i - (n - 1))
print(tmp)
for k in range(1, m):
tmp += diff[k - 1]
print(tmp)
if __name__ == '__main__':
main()

被折叠的 条评论
为什么被折叠?



