标签:技术 clu log style erro for 题目 blank void
题目链接:http://poj.org/problem?id=3744
题意:
有n个地雷,位置为pos[i]。
在每个位置,你向前走一步的概率为p,向前走两步的概率为1-p。
你的初始位置为1。
问你通过雷区的概率。
题解:
表示状态:
dp[i] = probability moving to i
表示走到i的概率
找出答案:
ans = dp[last_mine+1]
last_mine:最右边一颗雷的位置
如何转移:
dp[i] = dp[i-1] * p + dp[i-2] * (1-p)
if(i is a mine) dp[i] = 0
对于位置i,有可能是从i-1走来的,也有可能是从i-2走来的。
加法原理。
边界条件:
dp[1] = 1
初始位置为1。
优化:
矩阵快速幂。
对于某一段没有地雷的区间,是满足矩阵快速幂的(只用到递推式,dp不改为0)。
所以分段进行矩阵快速幂。
将雷区划分为n段:
1~pos[1], pos[1]+1~pos[2], pos[2]+1~pos[3]...
容斥原理:P(通过某一段雷区) = 1 - P(踩到最右边的雷)
乘法原理:P(通过总雷区) = ∏ P(通过每一段雷区)
矩阵格式:
初始矩阵:
特殊矩阵:
AC Code:
1 // state expression: 2 // dp[i] = probability moving to i 3 // 4 // find the answer: 5 // dp[last mine + 1] 6 // 7 // transferring: 8 // dp[i] = dp[i-1] * p + dp[i-2] * (1-p) 9 // 10 // boundary: 11 // dp[1] = 1 12 // others = 0 13 // 14 // optimization: 15 // quick pow for matrix 16 // from x to y 17 // res = start * special ^ (y-x) 18 // dp[i] = res.val[0][0] 19 #include <iostream> 20 #include <stdio.h> 21 #include <string.h> 22 #include <algorithm> 23 #define MAX_N 15 24 #define MAX_L 5 25 26 using namespace std; 27 28 struct Mat 29 { 30 int n; 31 int m; 32 double val[MAX_L][MAX_L]; 33 Mat() 34 { 35 n=0; 36 m=0; 37 memset(val,0,sizeof(val)); 38 } 39 void print_mat() 40 { 41 for(int i=0;i<n;i++) 42 { 43 for(int j=0;j<m;j++) 44 { 45 cout<<val[i][j]<<" "; 46 } 47 cout<<endl; 48 } 49 cout<<endl; 50 } 51 }; 52 53 int n; 54 int pos[MAX_N]; 55 double p; 56 double ans; 57 58 Mat make_unit(int k) 59 { 60 Mat mat; 61 mat.n=k; 62 mat.m=k; 63 for(int i=0;i<k;i++) 64 { 65 mat.val[i][i]=1; 66 } 67 return mat; 68 } 69 70 Mat make_start() 71 { 72 Mat mat; 73 mat.n=1; 74 mat.m=2; 75 mat.val[0][0]=0; 76 mat.val[0][1]=1; 77 return mat; 78 } 79 80 Mat make_special() 81 { 82 Mat mat; 83 mat.n=2; 84 mat.m=2; 85 mat.val[0][0]=0; 86 mat.val[0][1]=1-p; 87 mat.val[1][0]=1; 88 mat.val[1][1]=p; 89 return mat; 90 } 91 92 Mat mul_mat(const Mat &a,const Mat &b) 93 { 94 Mat c; 95 if(a.m!=b.n) 96 { 97 cout<<"Error: mul_mat"<<endl; 98 return c; 99 } 100 c.n=a.n; 101 c.m=b.m; 102 for(int i=0;i<a.n;i++) 103 { 104 for(int j=0;j<b.m;j++) 105 { 106 for(int k=0;k<a.m;k++) 107 { 108 c.val[i][j]+=a.val[i][k]*b.val[k][j]; 109 } 110 } 111 } 112 return c; 113 } 114 115 Mat quick_pow_mat(Mat mat,long long k) 116 { 117 Mat ans; 118 if(mat.n!=mat.m) 119 { 120 cout<<"Error: quick_pow_mat"<<endl; 121 return ans; 122 } 123 ans=make_unit(mat.n); 124 while(k) 125 { 126 if(k&1) 127 { 128 ans=mul_mat(ans,mat); 129 } 130 mat=mul_mat(mat,mat); 131 k>>=1; 132 } 133 return ans; 134 } 135 136 void read() 137 { 138 pos[0]=0; 139 for(int i=1;i<=n;i++) 140 { 141 cin>>pos[i]; 142 } 143 } 144 145 void solve() 146 { 147 sort(pos+1,pos+1+n); 148 Mat special=make_special(); 149 ans=1; 150 for(int i=1;i<=n;i++) 151 { 152 Mat start=make_start(); 153 Mat res=mul_mat(start,quick_pow_mat(special,pos[i]-pos[i-1])); 154 ans*=(1-res.val[0][0]); 155 } 156 } 157 158 void print() 159 { 160 printf("%.7f\n",ans); 161 } 162 163 int main() 164 { 165 while(cin>>n>>p) 166 { 167 read(); 168 solve(); 169 print(); 170 } 171 }
标签:技术 clu log style erro for 题目 blank void
原文地址:http://www.cnblogs.com/Leohh/p/7465622.html