题目:
有一个长度为n的序列,由 0 和m之间的整数组成,
可以按顺序执行以下操作1和2。
对于每个等于0的元素 ,分别在1 和 m之间随机选择一个整数,并替换为该元素。
按升序排序。
思路:
qwq没思路,看的官方题解
利用这一转换,分类讨论。
利用期望的线性性,叠加讨论 1 到m的情况。
如果对于 ,若在序列中存在 n - k + 1 及以上个大于等于 i 的元素。那么该情况对答案的贡献为1。因为不管其他可变项如何取值,都无法改变第k个元素大于等于i的事实。如果存在大于等于k个元素小于i ,那么这种情况对答案的贡献为0。因为无论其他可变项如何取值都不能使得第k个元素大于等于i
除上面两种情况,剩下的就是将可变项的一部分,取值为大于等于0的值,从而使得在排序之后第k个元素的值要大于等于i。令可变项的个数为 cnt0,大于等于i的个数为cnt1,小于i的个数为cnt。从cnt0中选取j个元素。
#include <bits/stdc++.h>
#define oo 0x3f3f3f3f
#define ll long long
#define OO 0x3f3f3f3f3f3f3f3f
#define IO ios::sync_with_stdio(false);cin.tie(nullptr)
#define endl "\n"
#define int ll
const int N = 2e3 + 10, M = 2 * N;
using namespace std;
typedef pair<int, int> pii;
#define deb(i,x) if(int i==x) int k = 1;
#define all(x) x.begin(),x.end()
ll lowbit(ll x) { return x & -x; }
ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
ll qmi(ll a, ll b, ll mod)
{
ll res = 1;
while(b)
{
if(b & 1) res = res * a % mod;
b >>= 1;
a = a * a % mod;
}
return res % mod;
}
const int mod = 998244353;
int c[N][N]={0};
int n, m, k;
void init(){
for(int i = 0;i < N;i ++)
for(int j = 0;j <= i;j ++)
if(!j)c[i][j] = 1;
else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}
signed main(){
IO;
cin >> n >> m >> k;
init();
vector<int> a(n + 1);
int cnt0 = 0;
for(int i= 1;i <= n;i ++)
{
cin >> a[i];
if(!a[i])cnt0 ++;
}
int ans = 0;
//cout << "---" << endl << cnt0 << endl;
for(int i = 1;i <= m; i++)
{
int cnt1 = 0;//小于 i
for(int j = 1;j <= n;j ++)
if(!a[j]) continue;
else if(a[j] >= i)cnt1 ++;
int cnt = n - cnt0 - cnt1;// 大于等于 i
//cout << "cnt1 : " << cnt1 << endl;
if(cnt1 > n - k + 1 || cnt >= k)
{
ans = (ans + (cnt1 >= n - k + 1)) % mod;
continue;
}
int p = (m + 1 - i) * qmi(m, mod - 2, mod) % mod;
int tem = ((1 - p) % mod + mod) % mod;
for(int j = n - k + 1 - cnt1;j <= cnt0;j ++)
{
int lri = qmi(tem, cnt0 - j, mod);
int lei = qmi(p, j, mod);
int res = c[cnt0][j] % mod * lri % mod * lei % mod;
ans = (ans + res) % mod;
}
}
cout << ans << endl;
return 0;
}