qoj2607 Survey

题意

\(n\) 个人,\(m\) 元钱,每个人有一个最低要求工资 \(a_i\)。你需要把 \(m\) 元分成 \(n\) 份工资,每个人会随机得到一份,使得满足最低要求工资的人数期望最多。

\(n\le 1000,m\le 5000\)

思路

考虑期望的线性性质,满足最低要求工资的人数即每个人能满足要求的概率之和,即 \(ans=\sum_{i=1}^n p_i\)

对于每个人来说,满足条件概率即为分到大于等于 \(a_i\) 工资的概率,即 \(p_i=\frac{\sum_{j=1}^n [x_j\ge a_i]}{n}\)

最后则有 \(ans=\frac{\sum_{i=1}^n\sum_{j=1}^n [x_j\ge a_i]}{n}\)

于是我们设 \(f_{i,j}\) 表示将 \(j\) 元钱分成了 \(i\) 份工资时 \(\sum_{i=1}^n\sum_{j=1}^n [x_j\ge a_i]\) 的最大值,且每份工资单调不递增

假设增加了一份 \(k\) 元的工资,则该值会增加 \(\sum_{i=1}^n [a_i\ge k]\),可以使用前缀和处理。

由于每份工资单调不递增,所以第 \(i\) 份工资的上限即为 \(\lfloor\frac{m}{i}\rfloor\),因为要保证前面的工资都大于这份工资。

\(c_i=\sum_{i=1}^n [a_i\ge k]\) 于是就有:

\[f_{i,j}=\max\{f_{i-1,j-k}+c_k\} \pod{1\le i\le n,0\le j\le m,0\le k\le \min(j,\lfloor\frac{m}{i}\rfloor)} \]

最后 \(\frac{f_{n,m}}{n}\) 即为答案,复杂度 \(O(nm\log m)\)

代码

#include <bits/stdc++.h>
using namespace std;
#define ll long long
int n,m,c[5005];
double f[1005][5005];
signed main() {
	cin>>n>>m;
	for(int x,i=1;i<=n;i++)
		cin>>x,c[x]++;
	for(int i=1;i<=m;i++)
		c[i]+=c[i-1];
	for(int i=1;i<=n;i++){
		for(int j=0;j<=m;j++){
			for(int k=0;k<=min(j,m/i);k++){
				f[i][j]=max(f[i][j],f[i-1][j-k]+c[k]);
			}
		}
	}
	printf("%.15lf",f[n][m]/n);
	return 0; 
}
posted @ 2025-09-11 15:11  WuMin4  阅读(21)  评论(0)    收藏  举报