Codeforces 1156F Card Bag

Codeforces 1156F Card Bag

题目链接

https://codeforces.com/contest/1156/problem/F

题目大意

有 $n$ 个卡片,每个卡片上的数字为 $a_i$ 。每次等概率从这对卡里面抽出一个卡,假设 $x$ 为本次抽出来的卡片, $y$ 为上一次抽出的卡片,那么如果 $x < y$ 那么你就输了;如果 $x = y$ 你就获胜;如果 $x > y$ 那么比赛会继续。问你获胜的概率为多少。

题目分析

定义 $f[i][j]$ 为取大小为 $i$ 的数 $1$ 次,且这是取出来的第 $j$ 个数的概率为多少。那么显然有:

$$f[i][j] = \sum\limits_{k=1}^{i-1}{f[k][j – 1] \cdot \frac{cnt[i]}{n – j + 1}}$$

其中 $cnt[i]$ 为 $i$ 的出现次数。

注意到其中的求和可以使用前缀和来优化。

统计答案时只需要统计其中 $cnt[i] > 1$ 且连续取出来两次的情况即可。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>

using namespace std;

const int maxn = 5005;
long long mod = 998244353;

int n, m, t;

long long inv[maxn];
long long cnt[maxn];

long long f[maxn][maxn];

int read(){
	int x;
	scanf("%d", &x);
	return x;
}

long long qpow(long long b, long long x){
	long long ret = 1;
	
	while(x){
		if(x & 1){
			ret = ret * b % mod;
		}
		
		x >>= 1;
		b = b * b % mod;
	}
	
	return ret;
}

int main(){
	int i, j;
	int x, y;
	long long ans = 0;
	
	for(i=1;i<=5000;i++){
		inv[i] = qpow(i, mod - 2);
	}
	
	n = read();
	
	for(i=1;i<=n;i++){
		x = read();
		cnt[x]++;
	}
	
	for(i=1;i<=n;i++){
		f[i][1] = cnt[i] * inv[n] % mod;
		if(cnt[i] > 1)ans += cnt[i] * (cnt[i] - 1) % mod * inv[n] % mod * inv[n - 1] % mod;
		ans %= mod;
		f[i][1] += f[i - 1][1];
		for(j=2;j<=n;j++){
			f[i][j] = f[i - 1][j - 1] * cnt[i] % mod * inv[n - j + 1] % mod;
			if(cnt[i] > 1)ans += f[i - 1][j - 1] * cnt[i] % mod * (cnt[i] - 1) % mod * inv[n - j + 1] % mod * inv[n - j] % mod;
			ans %= mod;
			f[i][j] += f[i - 1][j];
		}
	}
	
	printf("%lld\n", ans);
	
	return 0;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据