码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 4599 Dice (概率DP+数学+快速幂)

时间:2016-08-04 23:16:52      阅读:228      评论:0      收藏:0      [点我收藏+]

标签:

题意:给定三个表达式,问你求出最小的m1,m2,满足G(m1) >= F(n), G(m2) >= G(n).

析:这个题是一个概率DP,但是并没有那么简单,运算过程很麻烦。

先分析F(n),这个用DP来推公式,d[i],表示抛 i 次连续的点数还要抛多少次才能完成。那么状态转移方程就是 d[i] = 1/6*(1+d[i+1]) + 5/6*(1+d[1]),

意思就是说在第 i 次抛和上次相同的概率是1/6,然后加上上次抛的和这一次,再加上和上次不同的,并且又得从第1次开始计算。

边界就是d[0] = 1/6*(1+d[1]) + 5/6*(1+d[1]), d[n] = 0;然后去解出d[1]来,然后把d[0]解出来,结果就是F(n) = (6^n-1)/5;

然后再去计算H(n) = 6 * F(n),当然也可以用DP来推,d[i]表示抛 i 次连续的1还要抛多少次才能完成,方程为d[i] = 1/6*(1+d[i+1]) + 5/6*(1+d[0]),

意思和上面差不多,就是改了一个d[0],因为是连续的1,如果不是1,就得从0开始。同样把d[0]解出来,即可。

G(n) = 6 * n;那就可以解出来m1, m2,m1 >= (6^n-1)/30, m2>=(6^n-1)/5,

很明显可以知道m1 = (6^n-1)/30, m2 = (6^n+24)/5,然后就能算出来,由于 n 比较大,还有除法,所以可以先把5,30的逆元先求出来,然后再进行计算。

5的逆元在这个题上是1609,30的逆元在这个题上是1944.然后用快速幂就可以求出来。

代码如下:

#include <cstdio>
#include <string>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <set>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <cctype>
using namespace std ;
typedef long long LL;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const double inf = 0x3f3f3f3f3f3f3f;
const double eps = 1e-8;
const int maxn = 56 + 5;
const int mod = 2011;
const int e5 = 1609;
const int e30 = 1944;
const int dr[] = {0, 0, -1, 1};
const int dc[] = {-1, 1, 0, 0};
int n, m;
inline bool is_in(int r, int c){
    return r >= 0 && r < n && c >= 0 && c < m;
}

LL quick_pow(LL a, LL b){
    LL k = a % mod;
    LL ans = 1;
    while(b){
        if(b & 1)  ans = (k * ans) % mod;
        b >>= 1;
        k = k * k % mod;
    }
    return ans;
}

int main(){
    LL n;
    while(cin >> n, n){
        LL a = quick_pow(6, n);
        LL ans1 = (a+24) * e30 % mod;
        LL ans2 = (a-1) * e5 % mod;
        cout << ans1 << " " << ans2 << endl;
    }
    return 0;
}

 

HDU 4599 Dice (概率DP+数学+快速幂)

标签:

原文地址:http://www.cnblogs.com/dwtfukgv/p/5738501.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!