quq

题意:

\(n(\leq 10^6)\) 个数的数组 \(a(a_i \leq 10^7)\),对于每一个 \(a_i\),操作一次可以等概率得到 \(1 \sim a_i\) 的任意一个数。
求在最优策略下,得到所有可能获得的数 \((1 \sim \max a_i)\) 的期望次数。

期望

首先,最优策略一定是将按 \(a\) 从大到小抽出数,没抽出就一直抽,因为在 \(a\) 较大可以抽出 \(a\) 较小的数,反过来就不可以。

对于一个要抽出来的数 \(i\), 那么就要找到一个最近的 \(a_i\), 记为 \(b\)

由于期望的线性性,考虑当前 \(i\) 的对总期望的贡献,要算出能单独抽出 \(i\) 期望次数和概率。

  1. 单独抽出 \(i\) 的期望就是 \(E(b)\),在 \(b\) 中抽出 \(i\), 就有:

\[E(b) = \sum_{i = 1}^{\infty} (\frac{b - 1}{b})^{i - 1}\cdot\frac{1}{b}\cdot i \]

\[b\cdot E(b) = \sum_{i = 1}^{\infty} (\frac{b - 1}{b})^{i - 1}\cdot i \]

\(k = \frac{b - 1}{b}\), 求:

\[\sum_{i = 1}^{\infty} k^{i - 1}\cdot i \]

注意到 \((k^{i})' = i \cdot k ^{i - 1}\), 对这个式子进行一个积分。

得到:

\[\sum_{i = 1}^{\infty} k^i \]

用生成函数表示:

\[f(x) = \frac{k}{1 - k} \]

导回去:

\[f'(x) = \frac{1 \cdot (1 - k) - (- 1) \cdot k}{(1 - k)^2} = \frac{1}{(1 - k)^2} = b^2 \]

因为:

\[b\cdot E(b) = f'(x) = b^2 \]

所以:

\[E(b) = b \]

  1. 求出概率,\(i + 1 \sim \max a_i\) 都抽完的概率。

\(s = \max a_i - i + 1\)

直接钦定 \(i\) 最后一个选,那么就有:

\[f_i = \frac{(s - 1)!}{s!} = \frac{1}{s} \]

求和即可

\[\text{ans} = \sum_{i = 1}^{\max a_i} i \times {f_i} \]

代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>

using namespace std;

template <typename T>
void Read(T &x) {
	x = 0; T f = 1; char a = getchar();
	for(; a < '0' || '9' < a; a = getchar()) if (a == '-') f = -f;
	for(; '0' <= a && a<= '9'; a = getchar()) x = (x * 10) + (a^ 48);
	x *= f;
} 
const int mod = 19260817;
int add(int a, int b) {
	int c = a + b;
	if (c < 0) c += mod;
	if (c >= mod) c -= mod;
	return c;
}
int mul(int a, int b) {
	return 1ll * a * b % mod;
}
int qpow(int a, int b) {
	int sum = 1;
	while(b) {
		if (b & 1) sum = mul(sum, a);
		a = mul(a, a);
		b >>= 1;
	}
	return sum;
}

const int MAXN = 1000010;
int n, m;
int a[MAXN];
int f[MAXN * 10], ifa[MAXN * 10];
int inv[MAXN * 10];

int main() {
	freopen("quq.in", "r", stdin);
	freopen("quq.out", "w", stdout); 
	Read(n); 
	int ma = 0;
	for(int i = 1; i <= n; i ++)
		Read(a[i]), ma = max(ma, a[i]);
	sort(a + 1, a + n + 1);
	inv[1] = 1;
	for(int i = 2; i <= ma; i ++)
		inv[i] = mul(mod - mod / i, inv[mod % i]);  
	int ans = 0;
	for(int i = n; i; i --)
		for(int j = a[i]; j > a[i - 1]; j--)
			ans = add(ans, mul(a[i], inv[a[n] - j + 1]));
	cout << ans;
	return 0;
}

posted @ 2022-03-16 09:17  qjbqjb  阅读(169)  评论(0编辑  收藏  举报