题意:一个序列A,现在两个人进行取数,取数规则如下:当前人取得数为位置在他上一次取数位置的右侧,取数的大小得大于之前两人取的所有数,存在可以取的数时随机取数,问取数个数的期望是多少
tip:pi各不相同
解析:明显的概率dp,我们用dp[i][j]表示上一个人取了大小为i数,当前取数人取了第j个位置上的数,则dp[i][j]=
∑
k
=
1
n
\sum_{k=1}^n
∑k=1ndp[j][k]/cnt+cnt,cnt为可取的k的个数,k满足arr[k]>arr[j],则ans =
∑
1
=
1
n
\sum_{1=1}^n
∑1=1ndp[0][i],然后再出去n,因为第一个人去1-n个位置的概率都是1/n
部分在代码中解释
AcCode:
#include<iostream>
#include<algorithm>
#define int long long
const int N = 5010;
const int mod = 998244353;
int arr[N];
int invf[N];
int dp[N][N];
inline int quick_pow(int a, int b = mod - 2) {
int ans = 1;
a %= mod;
while (b) {
if (b & 1) ans = ans * a % mod;
b >>= 1;
a = a * a % mod;
}
return ans;
}
inline void init(int n) {
for (int i = 1; i <= n; i++) {
invf[i] = quick_pow(i);
}
}
signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
int n;
std::cin >> n;
init(n);
for (int i = 1; i <= n; i++) std::cin >> arr[i];
for (int i = n; i; i--) {//第一个人取的数的大小
int cnt = 0;//满足条件的个数
int sum = 0;//满足条件的期望和
for (int j = n; j >= 0; j--) {//第二个人取得位置
if (arr[j] > i) {
cnt++;
sum = (sum + dp[i][arr[j]]) % mod;//dp[i][j],当j大于i时一定都处理好了,因为处理是从第二维从大到下处理的
}
else if (arr[j] < i) {
dp[arr[j]][i] = (sum * invf[cnt] % mod + 1ll) % mod;//自身还有1
}
}
}
int ans = 0;
for (int i = 1; i <= n; i++) {
ans = (ans + dp[0][i]) % mod;
}
std::cout << ans * invf[n] % mod << std::endl;
}