[CF183D]T-shirt
题面在这里
description
\(n\)个人,\(m\)种大小的衣服,第\(i\)个人是第\(j\)种大小的概率是\(p_{i,j}\)。
选择\(n\)件衣服,最大化合适衣服的期望。
data range
\[n≤3000,m≤300
\]
solution
首先仍然把每种T-shirt分开考虑,即如果我们对于某种大小的衣服选的数量一定,
那么最后这种大小的衣服合适的数量期望是一定的;
考虑\(DP\),对于第\(k\)种大小的衣服,
设\(f[i][j]\)表示前\(i\)个人中适合人数为\(j\)的期望,那么有
\[f[i][j]=f[i-1][j-1]\times p[i][j]+f[i-1][j]\times (1-p[i][k])
\]
设\(g[i]\)表示这种大小的衣服固定选\(i\)件的期望,那么有
\[g[i]=\sum_{j=0}^{i}j\times f[n][j]+\sum_{j=i+1}^{n}i\times f[n][j]
\]
于是我们可以把每一种大小看成一组物品,用分组背包来做这道题,
复杂度为\(O(n^2m)\)
如果我们能够看到
\[g[i+1]-g[i]=\sum_{j=i+1}^{n}f[n][j]=1-\sum_{j=0}^{i}f[n][j]
\]
即差值递减,那么我们可以知道\(g[i]\)函数单峰
正因如此,我们动态地看这个挑选衣服的问题,
如果我们每次从\(m\)中衣服里挑选\(\Delta=g[i+1]-g[i]\)(\(i\)表示当前选择的衣服件数)
最大的一个,那么可以保证**之后所有选择的$\Delta'\le\Delta \(**
因此这样贪心选出的\)Ans=\sum\Delta$一定不会比最优方案更
实现:
首先\(O(nm)\)地预处理和算出每个尺寸的\(\Delta=g[1]-g[0]=1-f[n][0]\)
之后每次选出一个最大的\(\Delta\),将该种颜色衣服的\(\Delta\)重新计算,
根据预处理\(\Delta\)的复杂度可以分为\(O(n^2+nm)\)或\(O(n^2+nlogm)?\)
这里只需要\(O(n^2+nm)\)即可
code
#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<complex>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define mp make_pair
#define pub push_back
#define puf push_front
#define pob pop_back
#define pof pop_front
#define RG register
#define il inline
using namespace std;
typedef unsigned long long ull;
typedef vector<int>VI;
typedef long long ll;
typedef double dd;
const dd eps=1e-10;
const int mod=1e8;
const int N=3010;
const int M=305;
il ll read(){
RG ll data=0,w=1;RG char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
return data*w;
}
il void file(){
freopen(".in","r",stdin);
freopen(".out","w",stdout);
}
int n,m;dd p[N][M],d[M],f[M][N],c[M],l[N],ans;
il void init(){
for(RG int i=1;i<=m;i++){
f[i][0]=1;
for(RG int j=1;j<=n;j++)
f[i][j]=f[i][j-1]*(1-p[j][i]);
d[i]=1-f[i][n];
}
}
il void update(int k){
swap(f[k],l);f[k][0]=0;//注意此处
for(RG int i=1;i<=n;i++)
f[k][i]=l[i-1]*p[i][k]+f[k][i-1]*(1-p[i][k]);
c[k]++;d[k]-=f[k][n];
}
int main()
{
n=read();m=read();
for(RG int i=1;i<=n;i++)
for(RG int j=1;j<=m;j++)
p[i][j]=read()*1.0/1000;
init();
for(RG int i=1,k;i<=n;i++){
k=0;
for(RG int j=1;j<=m;j++)
if(d[k]<d[j])k=j;
if(!k)break;
ans+=d[k];update(k);
}
printf("%.12lf\n",ans);
return 0;
}

浙公网安备 33010602011771号