首先我们先考虑期望要买多少张,我们设计状态是F[i]表示已有i张,要集齐n张还要买几张。为什么我们不直接设计状态F[i]为:有i张邮票的期望购买次数呢?因为你如果设计成这个状态的话就无法转移,你可以将状态之间用一个有向图表示,其中边权为转移的概率,那么我们发现一个状态的出边的边权和为1,如果你设计的是第二种状态,我们会发现转移出去的概率和是不等于1的。那我们就得到转移方程为 F[i]=(i/n)*(F[i]+1)+((n-i)/i)*(F[i+1]+1)。

但是我们发现钱数并不好统计,因为买第k张的钱数是k,而我们设计的状态是收集了i种时还要再买几张,因此我们可以这样等价转化一下,我们认为1张邮票的代价是1元,如果买了这个邮票,那么后面的邮票价格全都加1,那我们设计状态G[i]表示已有i张,要集齐n张还要花多少钱,那么我们就有:G[i]=(i/n)(G[i]+1+F[i])+((n-i)/n)(G[i+1]+1+F[i+1]),可以这样理解:如果这次买的和之前的相同,那么后面买的F[i]张价格全都上升1,如果买的和之前的不同,那么后面买的F[i+1]张价格全都上升1,再加上这张的价格1,相当与是费用提前计算。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 #define maxn 10005
 6 double f[maxn],g[maxn];
 7 int n;
 8 
 9 int main()
10 {
11     scanf("%d",&n);
12     for (int i=n-1;i>=0;i--)
13         f[i]=f[i+1]+(double)n/(n-i);
14     for (int i=n-1;i>=0;i--) 
15         g[i]=g[i+1]+f[i+1]+((double)(n*i)/((n-i)*n))*f[i]+((double)n/(n-i));
16     printf("%.2f\n",g[0]);
17     return 0;
18 }

 

posted on 2017-05-29 08:07  Vergil_LY  阅读(207)  评论(0编辑  收藏  举报