题意
解法
这是一道神奇的题目。
显然,我们可以对每个假钞分别考虑。
令
表示第i种假钞最终持有者大于等于j个人的概率。
那么我们相当于求所有
前n大的和。
注意到,当i确定后,随着j的递增,
递减。
于是考虑归并排序。
每次取出当前最大的种类,并在
的时间内扩展到这个种类的下一个j。
时间复杂度:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
int n,m;
#define Maxn 3005
double p[3005][305];
double f[305][Maxn];
inline void gao(int x){
double pre=f[x][0];
f[x][0]=0.0;
for(register int i=1;i<=n;++i){
double tmp=f[x][i];
f[x][i]=f[x][i-1]*(1.0-p[i][x])+p[i][x]*pre;
pre=tmp;
}
}
int main(){
scanf("%d%d",&n,&m);
for(register int i=1;i<=n;++i)
for(register int j=1;j<=m;++j){
scanf("%lf",&p[i][j]);
p[i][j]/=1000.00;
}
for(register int i=1;i<=m;++i){
double tmp=1.0;
f[i][0]=0.0;
for(register int j=1;j<=n;++j)f[i][j]=p[j][i]+f[i][j-1]*(1.0-p[j][i]);
}
double Ans=0.0;
for(register int i=1;i<=n;++i){
double tmp=0.0;
int id;
for(register int j=1;j<=m;++j)
if(f[j][n]>tmp){
tmp=f[j][n];
id=j;
}
Ans+=tmp;
gao(id);
}
printf("%.10lf\n",Ans);
return 0;
}