1. 程式人生 > >oj練習---dp專題

oj練習---dp專題

1.POJ 3744  Scout YYF I

經典的dp模型,但是要用到快速矩陣冪加速,分段的思想 

# include <stdio.h>
# include <algorithm>
# include <string.h>
# include <iostream>
using namespace std;

int mines[15];

void matrixMulti(double a[2][2], double b[2][2]){
    double i,j,k,l;
    i = a[0][0]*b[0][0]+a[0][1]*b[1][0];
    j = a[0][0]*b[0][1]+a[0][1]*b[1][1];
    k = a[1][0]*b[0][0]+a[1][1]*b[1][0];
    l = a[1][0]*b[0][1]+a[1][1]*b[1][1];
    a[0][0]=i,a[0][1]=j,a[1][0]=k,a[1][1]=l;
}

double quickPow(const double p, int x){
    if(x == -1){
        return 1.0;
    }
    double a[2][2] = {0, 1, 1-p, p}, res[2][2] = {1,0,0,1};
    while(x){
        //printf("this 3\n");
        if(x&1){
            matrixMulti(res, a);
        }
        x/=2;
        matrixMulti(a,a);
    }
    return res[0][1]*(1-p);
}

int main(){
    int num;
    double p, result;
    while(scanf("%d%lf",&num, &p) != EOF){
        memset(mines, 0, sizeof(mines));
        for(int i = 1 ; i <= num; ++i){
            scanf("%d", mines + i);
        }
        if(mines[1] == 1){
            printf("%.7f\n", 0.0);
            continue;
        }
        mines[0] = 0;
        result = 1.0;
        sort(mines, mines+num+1);
        for(int i = 1; i <= num; ++i){
            result *= quickPow(p, mines[i] - mines[i - 1] - 1);
        }
        if(result < 0){
            result = 0;
        }
        if(result > 1){
            result =1;
        }
        printf("%.7f\n", result);
    }
    return 0;
}

心得:1.dp[i]=dp[i-2]*(1-p)+dp[i-1]*p,其實就是連續跟1-p/p相乘,自然想到矩陣加速。2.快速冪的思想,將O(n)降成O(lg(n))。

3.[0, 1; 1-p, p]  * [dp[i-2]; dp[i-1]] =  [dp[i-1]; dp[i]],然後變成冪運算之後就可以加速了。多次乘以相同的數值其實就是冪運算(一個數就是整數冪,多個數的式子就是矩陣冪)