HDU 4652 Dice:期望dp(成环)【错位相减】

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4652

题意:

  给你一个有m个面的骰子。

  两种询问:

    (1)"0 m n": “最后n次点数均相同”的投掷次数期望。

    (2)"1 m n": “最后n次点数各不相同”的投掷次数期望。

 

题解:

  表示状态:

    dp[i] = expectation (当前已经有i个点数相同/不相同)

 

  找出答案:

    ans = dp[0]

 

  如何转移:

  一、都相同

    (1)dp[i] = dp[i+1]/m + dp[1]*(1-1/m) + 1 (要么与前面相同,要么不同)

    (2)dp[i+1] = dp[i+2]/m + dp[1]*(1-1/m) + 1 (为了错位相减消去后面的dp[1],令i = i+1)

    (1)-(2)得:

      dp[i] - dp[i+1] = (dp[i+1] - dp[i+2])/m

    设d[i] = dp[i] - dp[i+1],有d[i+1]= dp[i]*m (d[i]可递推)

    则:dp[0] - dp[n] = sigma(d[0 to n-1]) (前后两项相消)

    又因为:dp[n] = 0

    所以:dp[0] = sigma(d[0 to n-1]),枚举求和即可。

 

  二、都不同

    (1)dp[i] = dp[i+1]*(m-i)/m + dp[i]/m + dp[i-1]/m +...+ dp[1]/m + 1 (要么与之前均不同,要么与第n,n-1,n-2...1位相同)

    (2)dp[i+1] = dp[i+2]*(m-i-1)/m + dp[i+1]/m + dp[i]/m +...+ dp[1]/m + 1 (令i = i+1,错位相减)

    (1)-(2)得:

      dp[i] - dp[i+1] = (dp[i+1] - dp[i+2])*(m-i-1)/m

    设d[i] = dp[i] - dp[i+1],有d[i+1]= dp[i]*m/(m-i-1) (d[i]可递推)

    则:dp[0] - dp[n] = sigma(d[0 to n-1])

    同一中:dp[0] = sigma(d[0 to n-1]) 即为答案。

 

AC Code:

  1 // PROB 1: is the same
  2 //
  3 // state expresssion:
  4 // dp[i] = expectation
  5 // i: the same numbers
  6 //
  7 // find the answer:
  8 // ans = dp[1] + 1
  9 //
 10 // transferring:
 11 // dp[i] = dp[i+1]/m + dp[1]*(1-1/m) + 1
 12 // dp[i+1] = dp[i+2]/m + dp[1]*(1-1/m) + 1
 13 // dp[i] - dp[i+1] = dp[i+1]/m - dp[i+2]/m
 14 // dp[i] - dp[i+1] = (dp[i+1] - dp[i+2])/m
 15 // dp[i+1] - dp[i+2] = (dp[i] - dp[i+1])*m
 16 // d[0] = dp[0] - dp[1] = 1
 17 // dp[0] + dp[n] = sigma(d[0 to n-1])
 18 // dp[0] = sigma(d[0 to n-1])
 19 //
 20 //
 21 // PROB 2: is different
 22 //
 23 // state expression:
 24 // dp[i] = expectation
 25 // i: different numbers
 26 //
 27 // find the answer:
 28 // ans = dp[1] + 1
 29 //
 30 // transferring:
 31 // dp[i] = dp[i+1]*(m-i)/m + dp[i]/m + dp[i-1]/m +...+ dp[1]/m + 1
 32 // dp[i+1] = dp[i+2]*(m-i-1)/m + dp[i+1]/m + dp[i]/m +...+ dp[2]/m + dp[1]/m + 1
 33 // dp[i] - dp[i+1] = dp[i+1]*(m-i)/m - dp[i+2]*(m-i-1)/m - dp[i+1]/m
 34 // dp[i] - dp[i+1] = (dp[i+1] - dp[i+2])*(m-i-1)/m
 35 // dp[i+1] - dp[i+2] = (dp[i] - dp[i+1])*m/(m-i-1)
 36 // d[0] = dp[0] - dp[1] = 1
 37 // dp[0] + dp[n] = sigma(d[0 to n-1])
 38 // dp[0] = sigma(d[0 to n-1])
 39 #include <iostream>
 40 #include <stdio.h>
 41 #include <string.h>
 42 #define MAX_N 1000005
 43 
 44 using namespace std;
 45 
 46 int n,m,p,t;
 47 double ans;
 48 double dp[MAX_N];
 49 
 50 void read()
 51 {
 52     cin>>p>>m>>n;
 53 }
 54 
 55 void cal_dp_same()
 56 {
 57     // dp[i+1] - dp[i+2] = (dp[i] - dp[i+1])*m
 58     // dp[0] = sigma(d[0 to n-1])
 59     double d=1;
 60     ans=0;
 61     for(int i=0;i<n;i++)
 62     {
 63         ans+=d;
 64         d*=m;
 65     }
 66 }
 67 
 68 void cal_dp_dif()
 69 {
 70     // dp[i+1] - dp[i+2] = (dp[i] - dp[i+1])*m/(m-i-1)
 71     // dp[0] = sigma(d[0 to n-1])
 72     double d=1;
 73     ans=0;
 74     for(int i=0;i<n;i++)
 75     {
 76         ans+=d;
 77         d*=m/(m-i-1.0);
 78     }
 79 }
 80 
 81 void solve()
 82 {
 83     if(p==0) cal_dp_same();
 84     else cal_dp_dif();
 85 }
 86 
 87 void print()
 88 {
 89     printf("%.9f\n",ans);
 90 }
 91 
 92 int main()
 93 {
 94     while(cin>>t)
 95     {
 96         while(t--)
 97         {
 98             read();
 99             solve();
100             print();
101         }
102     }
103 }

 

dp[i] = dp[i+1]*(m-i)/m + dp[i]/m + dp[i-1]/m +...+ dp[1]/m + 1

posted @ 2017-09-24 00:26  Leohh  阅读(347)  评论(0编辑  收藏  举报