POJ 3744 Scout YYF I
概率$dp$,矩阵优化。
设$dp[i]$为到位置$i$存活的概率,那么如果位置$i$是雷区,$dp[i]=0$,否则$dp[i]=p*dp[i-1]+(1-p)*dp[i-2]$。求出最后一个雷区位置的后一个位置的$dp$值就是答案。长度较大,可以矩阵优化加速一下。输出%$lf$不让过,%$f$过了。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<iostream> using namespace std; typedef long long LL; const double pi=acos(-1.0),eps=1e-6; void File() { freopen("D:\\in.txt","r",stdin); freopen("D:\\out.txt","w",stdout); } template <class T> inline void read(T &x) { char c = getchar(); x = 0; while(!isdigit(c)) c = getchar(); while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); } } int n; double p,ans; int a[20]; struct Matrix { double A[4][4]; int R, C; Matrix operator*(Matrix b); }; Matrix X, Y, Z; Matrix Matrix::operator*(Matrix b) { Matrix c; memset(c.A, 0, sizeof(c.A)); int i, j, k; for (i = 1; i <= R; i++) for (j = 1; j <= b.C; j++) for (k = 1; k <= C; k++) c.A[i][j] = c.A[i][j] + A[i][k] * b.A[k][j]; c.R=R; c.C=b.C; return c; } void init(double p1,double p2) { Z.A[1][1] = p1, Z.A[1][2] = p2; Z.R = 1; Z.C = 2; Y.A[1][1] = 1, Y.A[1][2] = 0, Y.A[2][1] = 0, Y.A[2][2] = 1; Y.R = 2; Y.C = 2; X.A[1][1] = 0, X.A[1][2] = 1-p, X.A[2][1] = 1, X.A[2][2] = p; X.R = 2; X.C = 2; } void work(int x) { while (x) { if (x % 2 == 1) Y = Y*X; x = x >> 1; X = X*X; } Z = Z*Y; } int main() { while(~scanf("%d%lf",&n,&p)) { for(int i=1;i<=n;i++) scanf("%d",&a[i]); sort(a+1,a+1+n); if(a[1]==1) ans=0; else { bool flag=0; for(int i=1;i<n;i++) if(a[i]+1==a[i+1]) flag=1; if(flag==1) ans=0; else { double p1=0,p2=1; int pos=1, now=1; while(1) { if(a[now]!=pos+1) { init(p1,p2); work(a[now]-1-pos); p1=Z.A[1][1]; p2=Z.A[1][2]; pos=a[now]-1; } double np1=0,np2=(1-p)*p2; pos=pos+2; p1=np1; p2=np2; now++; if(now==n+1) break; } ans=p2; } } printf("%.7f\n",ans); } return 0; }