Scout YYF I POJ - 3744
题意:这个题意很好懂~就是讲一个人要走一条路(一维),从坐标1开始走,在当前位置他往前走一步的概率是P,走两步的概率是1-p。然后路上有n个炸弹,问能安全走完这段路的概率是多少。
分析:
状态转移: dp[i]=dp[i-1]p+dp[i-2](1-p);
然后如果i位置有炸弹的话dp[i]=0;
但是炸弹的位置可以到1e8,这个都存不下,如果存的下也会超时…
再看一下状态转移,这个递推式可以用矩阵快速幂呀。
因为炸弹的数量最多到10,就可以分成10段来看。
比如x处有炸弹,那么一定会走到x-1处,我们只用把x-1处的概率求出来就行了
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn = 1e6;
struct matrix
{
double mat[5][5];
matrix()
{
memset(mat,0,sizeof(mat));
}
};
matrix mul(matrix A,matrix B)
{
matrix C;
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
for(int k=0;k<2;k++)
{
C.mat[i][j]=C.mat[i][j]+A.mat[i][k]*B.mat[k][j];
}
}
}
return C;
}
matrix quickmi(matrix A,long long n)
{
matrix B;
for(int i=0;i<=2;i++)
B.mat[i][i]=1;
while(n>0)
{
if(n&1) B=mul(A,B);
A=mul(A,A);
n=n/2;
}
return B;
}
double temp[10];int x[20];
int main()
{
int n;double p;
while(scanf("%d %lf",&n,&p)!=EOF)
{
for(int i=0;i<n;i++)
scanf("%d",&x[i]);
sort(x,x+n);
if(n<1) {printf("1.0000000\n");continue;}
matrix A;
A.mat[0][0]=p,A.mat[0][1]=1.0-p;
A.mat[1][0]=1.0;A.mat[1][1]=0;
double ans=1.0;
matrix B;temp[0]=p;temp[1]=1;
int t=x[0];
t--;
if(t==0) {printf("0.0000000\n");continue;}
else if(t==1) {ans=ans*(1.0-p);}
else if(t==2) {ans=ans*p*(1-p);}
else {
matrix B=quickmi(A,t-2);
double a1=temp[0]*B.mat[0][0]+temp[1]*B.mat[0][1],a2=temp[0];
temp[0]=a1,temp[1]=a2;
ans=ans*a1*(1-p);
}
temp[0]=ans;temp[1]=0;
for(int i=1;i<n;i++)
{
t=x[i]-1;
t=t-(x[i-1]+1);
if(t<0) {ans=0;break;}//这里要注意不要掉了~
B = quickmi(A,t);
double a1=temp[0]*B.mat[0][0]+temp[1]*B.mat[0][1],a2=temp[0];
temp[0]=a1,temp[1]=a2;
ans=a1*(1-p);
temp[0]=ans;temp[1]=0;
}
printf("%.7f\n",ans);
}
return 0;
}