题目描述
有 n 个人排成一排,一开始全部面向前方,然后随机朝左或是朝右转。
然后我们不断审查这个队列,每次选择两个面对面的相邻的人,将他们从队列中取出。
例如(> 表示向右,< 表示向左):
队列 >>><<< 的消除过程为,>>><<< 到 >><< 到 >< 到空队列(每次去除一对)。
队列 >><><<<> 的消除过程为,>><><<<> 到 >><<<> 到 ><<> 到 <>(每次去除一对)。
求最后期望能够剩下多少人。
输入格式
一行一个正整数 n 。
输出格式
一行一个实数,表示期望剩下的人数,四舍五入保留三位小数。
样例输入
10
样例输出
4.168
题解
我们考虑用dp[i][j]dp[i][j]来记录前ii个数中有j个人的概率,用表示前ii个数中有个人的期望.
想一想状态转移:
对于每一次状态,
dp[i+1][j+1]+=(dp[i][j])/2dp[i+1][j+1]+=(dp[i][j])/2;
dp[i+1][j−1]+=(dp[i][j])/2dp[i+1][j−1]+=(dp[i][j])/2,
f[i+1][j+1]+=(f[i][j]+dp[i][j])/2f[i+1][j+1]+=(f[i][j]+dp[i][j])/2;
f[i+1][j−1]+=(f[i][j]−dp[i][j])/2;f[i+1][j−1]+=(f[i][j]−dp[i][j])/2;
每一次要么就是增加一人,要么就是减少一人,所以每一种情况的概率为1212,所以此题中的价值为1,期望就等于概率,所以在转移f[][]f[][]时直接对概率操作就可以。
注意初始化
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
const int MAXN=2e3+2;
using namespace std;
int n;
double dp[MAXN][MAXN],f[MAXN][MAXN];
int main()
{
scanf("%d",&n);
dp[0][0]=1;
for(int i=0;i<n;i++)
{
dp[i+1][0]+=dp[i][0]/2;
dp[i+1][1]+=dp[i][0]/2;
f[i+1][0]+=(f[i][0]+dp[i][0])/2;
f[i+1][1]+=(f[i][0]+dp[i][0])/2;
for(int j=1;j<n;j++)
{
dp[i+1][j+1]+=(dp[i][j])/2;
dp[i+1][j-1]+=(dp[i][j])/2;
f[i+1][j+1]+=(f[i][j]+dp[i][j])/2;
f[i+1][j-1]+=(f[i][j]-dp[i][j])/2;
}
}
double ans=0;
for(int i=0;i<=n;i++)
ans+=f[n][i];
printf("%.3f",ans);
return 0;
}