POJ3744——概率DP 矩阵快速幂优化——Scout YYF I

http://poj.org/problem?id=3744

矩阵快速幂:

利用DP的递推式

就本题来说 dp[i] = p*dp[i-1] + (1-p)*dp[i-2]

由于x非常大最大1亿,这样的话复杂度就为1亿

所以这里可以用矩阵的思想

[dp[i]   dp[i-1] ] = [ dp[i-1]  dp[i-2] ] | p   1 - p| 

                                                      | 1      0  |

递推得到

                                                                   n - 1

[dp[n]   dp[n-1]] = [dp[1]   dp[2] ] |p   1 - p|            

                                                    |1      0 |

注意我这里分开了矩阵和行列式!!!

(由于忘了线代,纠结了四五天- - 一直以为最后一步还要做一次乘法)

题目说了第一步肯定走1 dp[1] = 1

然后就利用快速幂(只是把矩阵相乘用了这个思想优化)

11101

把所有乘法相当于变成了二进制,2^0 +2^2 + 2^3 + 2^4

如果有末尾1  那么乘上,每次把2自己翻倍

就是一开始 为2^0, 然后看见了最后这个1  总值*2^0      2^0 变成2^1

倒数第二个是0      总值还是原值    2*1 变成 2*2

......

要排序一下

这里注意当a[i] == a[i-1] 会出现幂为负数的情况,因为我这里写的是while(n) 这样就会出现死循环T了- - 特判掉。

还有最后输出要.7f..WA了

/************************************************
* Author        :Powatr
* Created Time  :2015-8-31 13:16:26
* File Name     :B.cpp
 ************************************************/

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
using namespace std;

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
typedef long long ll;
const int MAXN = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;

struct Matrix
{
    double a[2][2];
    void inti(){
        a[0][0] = a[1][1] = 1;
        a[1][0] = a[0][1] = 0;
    }
};
Matrix mul(Matrix a, Matrix b)
{
    Matrix ans;
    for(int i = 0 ; i < 2; i++){
        for(int j = 0; j < 2; j++){
           ans.a[i][j] = 0;
           for(int k = 0 ; k < 2; k++){
               if(a.a[i][k] == 0 || b.a[k][j] == 0) continue;
              ans.a[i][j] += a.a[i][k]*b.a[k][j];
           }
        }
    }
    return ans;
} 

Matrix pow_m(Matrix a, int n)
{
    Matrix ans;
    ans.inti();
    while(n){

        if(n&1) ans = mul(ans, a);
        n >>= 1;
        a = mul(a, a);
    }
    return ans;
}
double dp[11];
int b[11];
int main(){
    int n;
    double p;
    Matrix matrix;
    Matrix ret;
    while(~scanf("%d%lf", &n, &p)){
        double sum = 1;
        for(int i = 1; i <= n; i++)
            scanf("%d", &b[i]);
        sort(b + 1, b + n + 1);
                matrix.a[0][0] = p;
                matrix.a[0][1] = 1 - p;
                matrix.a[1][0] = 1;
                matrix.a[1][1] = 0;
        
        ret = pow_m(matrix, b[1] - 1);
        dp[1] = ret.a[0][0];
        sum *= (1 - dp[1]);
        for(int i = 2; i <= n; i++){
            if(b[i] == b[i-1]) continue;
            ret = pow_m(matrix, b[i] - b[i-1]- 1);
            dp[i] = ret.a[0][0];
            sum *= (1 - dp[i]);
        }
        printf("%.7f\n", sum);
    }
    return 0;
}

  

转载于:https://www.cnblogs.com/zero-begin/p/4772937.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值