这题好神啊……(然而我连每种物品贡献独立都没看出来……
首先$O(n^2 m)$的DP肯定都会写,然后可以发现每种物品一定是选得越多再选一个的收益就越低,因此可以用一个堆维护当前收益最高的物品,每次贪心取收益最高的那个并重新计算贡献……(当然不用堆也行,暴力扫就可以了……)
别问我为什么输出小数点后1000位,我不开心想调戏评测机玩……(然而好像到了一定位数之后就不会再输出了……所以我输出小数点后1亿位但实际上只输出了几百位的样子……
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<queue> 5 using namespace std; 6 const int maxn=3010,maxm=310; 7 struct A{ 8 int x; 9 double w; 10 A(int x,double w):x(x),w(w){} 11 bool operator<(const A &a)const{return w<a.w;} 12 }; 13 priority_queue<A>heap; 14 double p[maxn][maxm],f[maxn][maxm],g[maxn],ans=0.0; 15 int n,m; 16 int main(){ 17 scanf("%d%d",&n,&m); 18 for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){ 19 scanf("%lf",&p[i][j]); 20 p[i][j]/=1000.0; 21 } 22 for(int j=1;j<=m;j++){ 23 for(int i=1;i<=n;i++)f[i][j]=p[i][j]+f[i-1][j]*(1.0-p[i][j]); 24 heap.push(A(j,f[n][j])); 25 } 26 for(int i=1;i<=n;i++){ 27 A t=heap.top(); 28 heap.pop(); 29 ans+=t.w; 30 for(int i=1;i<=n;i++)g[i]=f[i-1][t.x]*p[i][t.x]+g[i-1]*(1-p[i][t.x]); 31 heap.push(A(t.x,g[n])); 32 for(int i=1;i<=n;i++)f[i][t.x]=g[i]; 33 } 34 printf("%.1000lf",ans); 35 return 0; 36 }