题意
一个圆盘,有N个区域,从1号出发,每次逆时针或顺时针向前走w步,问经过m次后,最终停留在区间【l,r】的概率。
有多个测试用例。
每个测试用例包含几行。
第一行包含四个整数:上述n(1≤n≤200)、m(0≤m≤1,000,000)、l,r(1≤l≤r≤n)。
然后是m行,每行代表一个命令。
命令是整数w(1≤w≤100),表示机器人将为该命令行走的单元长度。
输入端为n=0,m=0,l=0,r=0。
您不应该处理此测试用例。
输出量。
对于输入中的每个测试用例,您应该输出一行具有预期可能性的行。输出应四舍五入到小数点后的4位数字。
分析
dp【i】【j】表示第几次到大i点点概率
每次逆时针或顺时针向前走w步
所以dp【i】【j】=dp【(i+w)%n】【j-1】*0.5 +dp【(i-w+n)%n】【j-1】0.5
或者另一种思路是
dp[ (j+x-1)%n+1 ][!k] += 0.5 * dp[j][k];
dp[ (j+n100-x-1)%n+1 ][!k] += 0.5 * dp[j][k];
答案就是 把区间里的概率全部加起来
代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
int n, m, l, r, x;
double dp[205][2];
while(scanf("%d%d%d%d", &n, &m, &l, &r) == 4 && n+m+l+r)
{
memset(dp, 0, sizeof(dp));
dp[1][0] = 1.0;
int k = 1;
for(int i=0; i<m; i++)
{
scanf("%d", &x);
k = k ^ 1;
for(int j=1; j<=n; j++) dp[j][!k] = 0;
for(int j=1; j<=n; j++)
{
if(!dp[j][k]) continue;
dp[ (j+x-1)%n+1 ][!k] += 0.5 * dp[j][k];
dp[ (j+n*100-x-1)%n+1 ][!k] += 0.5 * dp[j][k];
}
}
double ans = 0.0;
for(int i=l; i<=r; i++) ans += dp[i][!k];
printf("%.4f\n", ans);
}
return 0;
}
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
double dp[210][2];
int main()
{
double ans;
int n,m,l,r,w;
while(scanf("%d%d%d%d",&n,&m,&l,&r)==4 && n+m+l+r)
{
dp[0][0] = 1;
for(int i = 1;i < n;i++)dp[i][0] = 0;
int t = 0;
while(m--)
{
int v;
scanf("%d",&v);
t^= 1;
for(int i = 0;i < n;i++)
dp[i][t] = 0.5*dp[(i-v+n)%n][t^1] + 0.5*dp[(i+v)%n][t^1];
}
double ans = 0.0;
for(int i = l-1;i < r;i++)
ans += dp[i][t];
printf("%.4lf\n",ans);
}
return 0;
}