题目大意:输入一个 N,然后在[1,N]范围内随机得到一个数字n,然后再随机得到一个长度为n的排列,设这个排列有
c
n
t
1
cnt1
cnt1个逆序对,在这个排列的基础上,生成一个子序列,,这个子序列的逆序对个数为
c
n
t
2
cnt2
cnt2个…,然后再从这个子序列循环下去直到最初生成的排列为空,问
c
n
t
1
+
c
n
t
2
+
.
.
.
+
c
n
t
n
cnt1 + cnt2 +...+ cntn
cnt1+cnt2+...+cntn的期望是多少
清华爷12分钟就A了,对于我来说感觉挺难想的吧…首先生成一个排列的概率要算,在生成的这个排列的上有多少个逆序对这不好想,但一个长度为 i i i排列最多有 i ∗ ( i − 1 ) 2 \frac{i * (i - 1)}{2} 2i∗(i−1)个逆序对,最少有0个逆序对,然后计算生成的排列逆序对个数为0到 N ∗ ( N − 1 ) 2 \frac{N * (N - 1)}{2} 2N∗(N−1)的排列的概率,这不现实,并且往下想会更加复杂。由于长度为 i i i 的 排列最多有 i ∗ ( i − 2 2 \frac{i * (i - 2}{2} 2i∗(i−2对位置,而每一对位置是逆序对的概率是 1 2 \frac{1}{2} 21 ,因此生成一个长为 i i i排列的逆序对个数的期望是 i ∗ ( i − 1 ) 4 \frac{i * (i - 1)}{4} 4i∗(i−1)。想到这感觉有了点思路,但接下来在这个排列的基础上生成的所有一个子序列的逆序对之和…由于生成一个长为 i i i的排列的概率是 1 N \frac{1}{N} N1,一个长为 i i i的序列最多有 1 2 i \frac{1}{2^i} 2i1,也就是说每一个子序列的概率为 1 2 i \frac{1}{2^i} 2i1,它所有的子序列的逆序对数应该是 0 到 i ∗ ( i − 1 ) 4 \frac{i * (i - 1)}{4} 4i∗(i−1),但具体概率是多少不知道…好,就猜它是等概率的,然后一算答案不对,思路就断片了。
(情况细分下来的概率难以计算…我始终以为这是可以计算的只是我没找到方法,放大了这道题的难度,阻扰思维,而又不愿退一步。有些题需要你更深一步去想,有些题需要你从另一些角度看待而不是深钻一个死胡同,而我总是徘徊在两种思维之间,找不到正确的方法,需要锻炼的地方就是这吧)
update:我发现我一开始理解题意是错的…
题解:随机生成的长度为
i
i
i 的排列的期望逆序对数是
i
∗
(
i
−
1
)
4
\frac{i * (i - 1)}{4}
4i∗(i−1) ,令DP[i] 为生成的序列长度为 i 的解,然后枚举长度 0 -> (i - 1) 转移即可。
(另外跟着标程走了一遍发现我自己的写法有很多可以优化的地方,这也是为什么常数老比别人大的原因吧…)
#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e3;
typedef long long ll;
const int mod = 998244353;
ll dp[maxn + 10];
ll pw[maxn + 10];
ll c[maxn + 10][maxn + 10];
ll ans[maxn + 10];
ll fpow(ll a,ll b) {
ll r = 1;
while(b) {
if(b & 1) r = r * a % mod;
a = a * a % mod;
b >>= 1;
}
return r;
}
int main() {
pw[0] = 1;
for(int i = 0; i <= maxn; i++) c[i][0] = c[i][i] = 1;
for(int i = 1; i <= maxn; i++) pw[i] = pw[i - 1] * 2 % mod;
for(int i = 2; i <= maxn; i++)
for(int j = 1; j <= i / 2; j++)
c[i][j] = c[i][i - j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod;
dp[0] = dp[1] = 0;
for(int i = 2; i <= maxn; i++) {
dp[i] = (i * (i - 1) % mod) * pw[i - 2] % mod;
for(int j = 0; j < i; j++)
dp[i] = (dp[i] + c[i][j] * dp[j] % mod) % mod;
dp[i] = dp[i] * fpow(pw[i] - 1,mod - 2) % mod;
}
ans[0] = 0;
for(int i = 1; i <= maxn; i++) {
ans[i] = 0;
for(int j = 1; j <= i; j++)
ans[i] = (ans[i] + dp[j]) % mod;
ans[i] = ans[i] * fpow(i,mod - 2) % mod;
}
int n;
while(~scanf("%d",&n))
printf("%lld\n",ans[n]);
return 0;
}