康复ing康复ing,不能出去给nju丢人qwq
题意:给n个数字,给k次机会,每次你可以随机取出一个数字,你有k次放回重新取数字的机会,你可以放弃一些机会不使用。请计算最终取得数字的最大期望。
题解:简单dp,记dp[i]为拥有i次机会,得到数字的最大期望,那么,如果这一次取得数字是vi>dp[i-1],显然,我们保留vi,放弃机会,得到期望vi,否则,vi<dp[i-1],则我们放回重取,得到期望是dp[i-1],于是dp[i] =sigma(max(vi,dp[i-1]))/n。
由于dp[i-1]为定值,我们可以对v事先排序,搭配后缀和,可以klogn完成这个dp过程。
Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxk = 5e4+100;
const int maxn = 2e4+100;
int v[maxn];
double dp[maxk];
LL sum[maxn];
void debug(int k){
for (int i=0;i<=k;i++){
printf("dp[%d]=%.3f\n",i,dp[i]);
}
}
void solve(int Cas){
int n,k;
scanf("%d%d",&n,&k);
LL Sum =0;
for (int i=0;i<n;i++){
scanf("%d",v+i);
Sum+=v[i];
}
sort(v,v+n);
sum[n]=0LL;
for (int i=n-1;i>=0;i--){
sum[i]=sum[i+1]+v[i];
}
dp[0] =1.0*Sum/n;
for (int i=1;i<=k;i++){
int limit = lower_bound(v,v+n,dp[i-1])-v;
// cout<<limit<<endl;
dp[i] = (sum[limit]+limit*dp[i-1])/(n*1.0);
}
// debug(k);
printf("Case #%d: %.6f\n",Cas,dp[k]);
}
int main(){
int T;
scanf("%d",&T);
for (int i=1;i<=T;i++){
solve(i);
}
return 0;
}