https://codeforces.com/contest/1753/problem/C
题目描述
给你一个长度为 n n n 的 01 01 01 序列,每次等概率随机交换序列中的一对数,如果它们是逆序对,则交换它们的位置,求排成顺序序列的期望操作次数。
Solution
t u t o r i a l tutorial tutorial 给出的是一个 D P DP DP 做法,这里说一下另一种从代码上来看很神仙的做法。
假设原序列为 [ 1010111001 ] [1010111001] [1010111001],排序后为 [ 0000111111 ] [0000111111] [0000111111],从形式上看等价于将最前的两个 1 1 1 与最后两个0做交换就完成了,其实实际上也是这样?做一个不严谨的说明:交换 a 3 a 4 a_3 a_4 a3a4 后序列为: [ 1001111001 ] [1001111001] [1001111001],这种交换其实是没有贡献的交换,将最后的0替换掉的交换才是“有效”交换。
于是大胆猜测柿子为
∑
j
=
1
m
∑
i
=
1
∞
i
∗
j
2
(
n
2
)
∗
(
1
−
j
2
(
n
2
)
)
i
−
1
\sum_{j=1}^m {\sum_{i=1}^\infty i*\frac {j^2} {\tbinom{n}{2}}*(1-\frac {j^2} {\tbinom{n}{2}})^{i-1}}
j=1∑mi=1∑∞i∗(2n)j2∗(1−(2n)j2)i−1解释一下:其中
m
m
m 为原序列中未归位
1
1
1 的数量,目前还有
j
j
j 个
1
1
1 未归位时,想实现一次“有效”交换,必须要选择一个末尾
0
0
0 和未归位
1
1
1 进行交换才可以,这两种数量都是
j
j
j,所以概率为
j
2
(
n
2
)
\frac {j^2} {\tbinom{n}{2}}
(2n)j2,然后就可推出上述柿子。
于是就可以用小学二年级知识开心的对上述柿子进行化简得到
a
n
s
=
(
n
2
)
∗
∑
i
=
1
m
1
i
2
ans = \tbinom{n}{2} * \sum_{i=1}^m {\frac 1 {i^2}}
ans=(2n)∗i=1∑mi21
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
int ksm(int a, int b){
int res = 1;
while (b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res%mod;
}
int n;
signed main(){
int t;
cin >> t;
while (t--){
int n;
cin >> n;
vector<int> a(n+1), b(n+1);
for (int i=1; i<=n; i++) {
cin >> a[i];
b[i] = a[i];
}
sort(b.begin(), b.end());
int m = 0;
for (int i=n; b[i]==1; i--) {
if(a[i]!=b[i]) m++;
} //统计未归位1个数
int res = 0;
for (int i=1; i<=m; i++) {
res += ksm(i,mod-2) * ksm(i,mod-2) % mod;
res %= mod;
}
cout << res * n % mod * (n-1) % mod * ksm(2ll,mod-2) % mod << '\n';
}
return 0;
}