POJ 3744

题意:人从1开始走,p的概率走1步,1-p的概率走2步,求踩雷的概率。

题解:走到第i位置的概率为f[i]=p*f[i-1]+(1-p)*(f[i-2]),利用矩阵快速幂可迅速求出f[i]。考虑成功通过第i个的雷的概率,应该等于没有踩中前(i-1)个雷的概率乘以没有踩中i的概率,而如果没有踩到i-1这颗雷,人必定是从mine[i-1]+1过来的,于是又变成和原来一样的解情况。考虑从1出发顺利通过位于x处的雷的概率,就应该等于一减去踩到x这个位置的概率,而踩到x的概率应该等于f[x],于是,得解。

View Code
 1 #include<cstdio>

 2 #include<cstring>

 3 #include<algorithm>

 4 using namespace std;

 5 double mat[200][2][2];

 6 void update(int ID)

 7 {

 8     memset(mat[ID],0,sizeof(mat[ID]));

 9     for(int i=0;i<2;i++)

10         for(int j=0;j<2;j++)

11             for(int k=0;k<2;k++)

12                 mat[ID][i][j]+=mat[ID-1][i][k]*mat[ID-1][k][j];

13 }

14 int mine[20];

15 int main()

16 {

17     int n;

18     double p;

19     while(scanf("%d%lf",&n,&p)!=EOF)

20     {

21         for(int i=0;i<n;i++)

22             scanf("%d",mine+i);

23         sort(mine,mine+n);

24         mat[0][0][0]=p;

25         mat[0][0][1]=1.0;

26         mat[0][1][0]=1.0-p;

27         mat[0][1][1]=0;

28         for(int i=1;i<200;i++)

29             update(i);

30         double ans=1;

31         int lx=1,len,k;

32         for(int i=0;i<n;i++)

33         {

34             len=mine[i]-lx;

35             double x[2],y[2];

36             x[0]=1.0;x[1]=0.0;

37             k=0;

38             while(len>0)

39             {

40                 if(len&1)

41                 {

42                     y[0]=x[0]*mat[k][0][0]+x[1]*mat[k][1][0];

43                     y[1]=x[0]*mat[k][0][1]+x[1]*mat[k][1][1];

44                     x[0]=y[0];x[1]=y[1];

45                 }

46                 len>>=1;

47                 k++;

48             }

49             ans*=(1-x[0]);

50             lx=mine[i]+1;

51         }

52         printf("%.7lf\n",ans);

53     }

54     return 0;

55 }

你可能感兴趣的:(poj)