HDU 4599 概率DP

先推出F(n)的公式:

设dp[i]为已经投出连续i个相同的点数平均还要都多少次才能到达目标状态。

则有递推式dp[i] = 1/6*(1+dp[i+1]) + 5/6*(1+dp[1]).考虑当前这一次掷色子,有1/ 6的概率投的和前面的一样,有5/6的概率不一样,不一样就要重新投,就到了dp[1]的状态,这里投了一次,所以要加1.边界有dp[0] = dp[1]+1,dp[n] = 0;

可以这么说,H[n]应该是6*F[n]的,随便YY一样。

更严谨的话就是一样要去推,递推式如下,设dp[i]为已经连续i次投出1后平均还要多少次才能达到目标状态。

有递推式dp[i] = 1/6*(dp[i+1]+1) + 5/6*(1+dp[0])(这里和上面的公式不一样)。边界条件dp[0] = 1/6*(1+dp[1]) +5/6*(dp[0]+1).dp[n]=0;逆着推就能直接求出dp[0].

推出来的F(n) = (6^n-1)/5,H(n) = 6*(6^n-1)/5.G(m) = 6*m,平均投6次会出现一次1.

或者概率DP,设dp[i]表示已经投出i次1平均还要投多少次才能到达目标状态。

则有dp[i] = 1/6*(1+dp[i+1]) + 5/6*(1+dp[i]).

边界条件dp[m]=0。

然后就得到m1>=(6^n-1)/30,m2>=(6^n-1)/5.显然最小的m2 = (6^n-1)/5

而(6^n-1)%30 !=0,通过观察发现有6%30=6,6*6%30=6,那么就有6^n%30=6也就是说虽然6^n%30 !=0,但是6^n+24%30 == 0,且这就是m1,

即有m1 = (6^n+24)/30.....现在就是求m1%2011,m2%2011,我是用的先算6^n%2011,用快速幂,然后求出分别求出30和5对应2011的逆元。

至于求逆元,用扩展欧几里得算法即可·······甚至用电脑暴力算出也行

贴代码:

 1 #include<cstdio>
 2 const int mod = 2011;
 3 const int e1 = 1944,e2 = 1609;//30,5的逆元
 4 inline int qPow(int x,int p)
 5 {
 6     int a=6,ans=1;
 7     while(x)
 8     {
 9         if(x&1) ans  = ans*a%p;
10         a = a*a%p;
11         x >>= 1;
12     }
13     return ans;
14 }
15 int main()
16 {
17 //    freopen("in.txt","r",stdin);
18     int n,tmp,tmp1,tmp2,ans1,ans2;
19     while(scanf("%d",&n),n)
20     {
21         tmp = qPow(n,mod);
22         tmp1 = (tmp+24+mod)%mod;
23         tmp2 = (tmp-1+mod)%mod;
24         ans1 = tmp1*e1%mod;
25         ans2 = tmp2*e2%mod;
26         printf("%d %d\n",ans1,ans2);
27     }
28     return 0;
29 }
View Code

 

 

 

 

 

 

posted on 2013-08-25 17:40  allh123  阅读(816)  评论(0编辑  收藏  举报

导航