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;
}