POJ 3744 Scout YYF I 概率DP+矩阵快速幂 好题

Scout YYF I
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 5731   Accepted: 1617

Description

YYF is a couragous scout. Now he is on a dangerous mission which is to penetrate into the enemy's base. After overcoming a series difficulties, YYF is now at the start of enemy's famous "mine road". This is a very long road, on which there are numbers of mines. At first, YYF is at step one. For each step after that, YYF will walk one step with a probability of p, or jump two step with a probality of 1-p. Here is the task, given the place of each mine, please calculate the probality that YYF can go through the "mine road" safely.

Input

The input contains many test cases ended with EOF.
Each test case contains two lines.
The First line of each test case is N (1 ≤ N ≤ 10) and p (0.25 ≤ p ≤ 0.75) seperated by a single blank, standing for the number of mines and the probability to walk one step.
The Second line of each test case is N integer standing for the place of N mines. Each integer is in the range of [1, 100000000].

Output

For each test case, output the probabilty in a single line with the precision to 7 digits after the decimal point.

Sample Input

1 0.5
2
2 0.5
2 4

Sample Output

0.5000000
0.2500000

Source

 
 
 
 
题意:一个特工在一条很远很远的布有地雷的路上走,这条路分成一个一个格子,编号从1开始
   然后特工走的时候,每次从i,会有p的概率走到i+1,会有1-p的概率走到i+2
   然后这条路上有n个地雷,n个地雷分别埋在这条路上的n个格子中,走到这些格子,当然就会boomboomboom
 
   给出n p
   然后是n个位置的编号
 
注意数据范围
 
n<=10,但是位置的编号是1<=编号<=100000000
 
开始时,概率DP
设dp[i]为从1走到i的概率
则:dp[i]=p*dp[i-1]+(1-p)*dp[i-2]
 
然而,这样要开100000000的数组,行不通
 
看这条递推式,想到什么?没错,就是矩阵的快速幂
 
这样还是要开啊
 
换个思路:
stp表示我现在的位置的编号
now表示我走到了这里的概率
pre表示我上一步的概率
则初始时:pre=1.0
        now=pre*p;
        stp=2  
设dp[i]表示走到第i个地雷时的概率,即走到pos[i]时的概率
,这样通过矩阵快速幂就可以求出走到pos[i]和pos[i]-1这2个位置的概率
然后dp[i]=0,所以要继续走,必须从pos[i]-1这个时候走2步到达pos[i]+1的位置时的概率了
然后更新stp,now,pre
pre=pos[i]+1时的概率
now=pre*p
stp=pos[i]+2
 
直到跨过了n个地雷
 
因为题目是要求成功走出通道的概率
只要特工跨过了这n个地雷后,就没有其他危险了,就一定可以走出通道了。
 
所以输出的是成功到达pos[n]+1的概率
 
 
犯了一个错误:n=n>>1被我写成了n==n>>1
导致无限循环,然后交上去tle了,我还以为是姿势不对。
 
这个程序0ms
 
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 
 5 using namespace std;
 6 
 7 #define LL long long
 8 
 9 struct Mat
10 {
11     double m[2][2];
12 };
13 Mat base;
14 
15 LL pos[15];
16 
17 Mat matmul(Mat a,Mat b)
18 {
19     Mat ret;
20     for(int i=0;i<2;i++)
21     {
22         for(int j=0;j<2;j++)
23         {
24             ret.m[i][j]=0.0;
25             for(int k=0;k<2;k++)
26             {
27                 ret.m[i][j]+=(a.m[i][k]*b.m[k][j]);
28             }
29         }
30     }
31     return ret;
32 }
33 
34 Mat matPow(Mat a,LL n)
35 {
36     Mat b;
37     b.m[0][0]=1;
38     b.m[0][1]=0;
39     b.m[1][0]=0;
40     b.m[1][1]=1;
41     while(n>0)
42     {
43         if(n&1)
44             b=matmul(b,a);
45         //刚开始这里写成了n==n>>1
46         //所以无限循环
47         //所以程序tle了
48         //还以为是我这个姿势不对
49         n=n>>1;
50         a=matmul(a,a);
51         //printf("%d\n",n);
52     }
53     return b;
54 }
55 
56 int main()
57 {
58     int n;
59     while(scanf("%d",&n)!=EOF)
60     {
61         double p;
62         scanf("%lf",&p);
63         for(int i=1;i<=n;i++)
64             scanf("%lld",&pos[i]);
65         sort(pos+1,pos+n+1);
66 
67         base.m[0][0]=p;
68         base.m[0][1]=1.0-p;
69         base.m[1][0]=1.0;
70         base.m[1][1]=0.0;
71 
72         double pre=1.0;
73         double now=p;
74         LL stp=2;
75         for(int j=1;j<=n;j++)
76         {
77             Mat tmp=base;
78             if(pos[j]-stp<0)
79             {
80                 pre=0.0;
81                 break;
82             }
83 
84             tmp=matPow(tmp,pos[j]-stp);
85 
86             double dp=tmp.m[1][0]*now+tmp.m[1][1]*pre;
87             pre=dp*(1.0-p);
88             now=pre*p;
89             stp=pos[j]+2;
90         }
91         printf("%.7f\n",pre);
92     }
93     return 0;
94 }
View Code

 

 
 
 
 
 
 
 
 
 
 
 
 
   
 
 
posted on 2015-05-22 21:46  _fukua  阅读(229)  评论(0编辑  收藏  举报