这个题当时就思路错掉了,样例都推不出来,看来想进google数学得过关。
题意就是给你一堆有权值的球,每次等概率拿一个,可以放回,有K次机会,求最大期望。其实我当时根本没在意最大期望和那句“如果你第K次拿了,那你就只能留在手里了”,看了官方分析才知道,这两句话有大用,不然就是求期望,而不是最大期望,吃了没文化的亏。
如果我没有选择权的时候,我只能拿到啥就算啥,于是乎K = 0的时候我能拿到的最大期望就是。
如果我有选择权,那就是另一个故事了。我如果有一次选择权我会怎么办,我就拿15 11 7 4 1这个样例来说吧。如果我手上本来就是15 11这样的(>E[0] = 7.8),我明显不用再丢回去铤而走险吧,因为丢回去了就一波定乾坤了,万一拿了个3乌龙了咋整。于是乎,我会选择,如果我第一次拿了3 5 7这样的比E[0]低的我才会把求丢回去再检验一波人品。这样我能拿到的期望就不一样了,我第一次拿了15和11,那我就不去玩下一波了,如果我拿了7 4 1(气死你?)那我就又获得了一次拿重新抽奖的机会,能抽到啥我不知道,但是期望值是E[0]没假。所以,后面就是依次类推了。如果你非要求概率那也是可以的,我会附上求概率的代码。
思路是这样:第一次拿球有一个期望E[0] = ,后面每一个放回拿球的期望E[i]都是要和前一次的期望做对比的,因为如果我第二次拿球拿的值还不如上一次的期望值高那我还拿干什么,所以E[i] =
。说实话,如果这个推不出来这个题小样例都过不去。太南了。
#include<bits/stdc++.h>
using namespace std;
double num[2*10240];
double sum[2*10240];
double E[5*10240];
int main()
{
int testcase;
cin >> testcase;
for(int kase = 1;kase<=testcase;kase++)
{
memset(num,0,sizeof(num));
memset(E,0,sizeof(E));
int n,K;
cin >> n >> K;
for(int i = 0;i < n;i++)
cin >> num[i];
sort(num,num + n);
sum[0] = num[0];
for(int i = 1;i < n;i++)
sum[i] = num[i] + sum[i-1];
for(int i = 0;i < n;i++)
E[0] += num[i];
E[0] /= n;
for(int i = 1;i <= K;i++)
{
int ind = lower_bound(num,num+n,E[i-1]) - num;
E[i] += ind * E[i-1];
//cout << E[i] << endl;
E[i] += sum[n-1]-sum[ind-1];
//cout << E[i] << endl;
E[i] /= n;
//cout << E[i] << endl;
}
printf("Case #%d: %.6lf\n",kase,E[K]);
}
return 0;
}
求概率,思路和上面一样,就是算了一下概率,比如说我要是第一次拿每个的概率都是1/n,如果我又一次重拿的机会,那我只需要把需要放回的那些再求一波概率。
#include<bits/stdc++.h>
using namespace std;
double num[2*10240];
double sum[2*10240];
double p[2*10240];
double E[5*10240];
int main()
{
int testcase;
cin >> testcase;
for(int kase = 1;kase<=testcase;kase++)
{
memset(num,0,sizeof(num));
memset(E,0,sizeof(E));
int n,K;
cin >> n >> K;
for(int i = 0;i < n;i++){
cin >> num[i];
p[i] = 1.0/n;
}
double P = 1.0/n;
sort(num,num + n);
sum[0] = num[0];
for(int i = 1;i < n;i++)
sum[i] = num[i] + sum[i-1];
for(int i = 0;i < n;i++)
E[0] += num[i];
E[0] /= n;
for(int i = 1;i <= K;i++)
{
int ind = lower_bound(num,num+n,E[i-1]) - num;
double tmp = 0;
for(int j = 0;j < ind;j++)
{
p[j] *= ind*1.0/n;
tmp += p[j];
E[i] += p[j] *num[j];
}
tmp = 1-tmp;
tmp /= (n-ind);
for(int j = ind;j < n;j++)
{
p[j] = tmp;
E[i] += p[j]*num[j];
}
}
printf("Case #%d: %.6lf\n",kase,E[K]);
}
return 0;
}