[POJ3744] Scout YYF I
[POJ3744] Scout YYF I
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
试题分析
列出一个复杂度为\(O(range)\)的式子非常简单。
但是要如何优化这个方程呢?
这里介绍一种分析技巧:\(f_i=f_{i-1}\times k+f_{i-2}\times (1.0-k)\)
设\(x=f_{i-1}\),\(y=f_{i-2}\),那么有\(f_i=x\times k +y - y\times k\)
容易证明,当存在两个连续的\(f_{i-1}=f_i\)时,以后都是一样的。
于是我们要证明\(f_i-f_{i-1}\)在精度误差下会收敛至0。
展开式子,发现含有k的项都是会收敛的。
那么经过若干次以后这些项收敛至0的时候就可以一直维持下去。
当然考场上可以打表嘛。。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define LL long long
inline int read(){
int x=0,f=1; char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const int INF = 2147483600;
const int MAXN = 100100;
int N; double k,f[MAXN+101]; int a[MAXN+1];
bool vis[MAXN+1];
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
while(scanf("%d",&N)!=EOF&&N){
scanf("%lf",&k); int las=0; memset(vis,false,sizeof(vis));
for(int i=1;i<=N;i++) a[i]=read(); sort(a+1,a+N+1);
if(a[1]>=3000) a[1]=3000; vis[a[1]]=true;
for(int i=2;i<=N;i++){
if(a[i]-las-a[i-1]>=3000) las+=a[i]-a[i-1]-3000,a[i]=a[i-1]+3000;
vis[a[i]]=true;
} memset(f,0,sizeof(f)); f[1]=1.0;
for(int i=2;i<=a[N]+3;i++){
if(vis[i]) continue;
if(i==2) f[i]=f[i-1]*k;
else f[i]=f[i-1]*k+f[i-2]*(1.0-k);
} printf("%.7lf\n",f[a[N]+1]);
}
return 0;
}