转自:https://blog.csdn.net/dcx2001/article/details/78036359
题目链接:https://cn.vjudge.net/problem/HDU-4576
题意:输入n,m,l,r。n是一圈的长度,数字是顺时针标记的。m是操作数,接下来有m行,每行都有一个数字w代表每次行走的步数,走顺时针逆时针的方向是等概率的,一开始在1处,求最后在【l,r】范围内的概率。
思路:f[i][j]表示第I个操作时在j位置的概率。因为空间限制,所以数组第一维是2。这里用到了异或的性质。即a^1=b。若a是偶数,则b=a+1,若a是奇数,则b=a-1。这样可以用异或表示这一轮的操作和上一轮的操作。
#include <bits/stdc++.h>
using namespace std;
double f[2][210];
int main()
{
int n,m,l,r,now,w;
while(scanf("%d%d%d%d",&n,&m,&l,&r))
{
if(!n&&!r&&!m&&!l)
break;
memset(f,0,sizeof(f));
f[0][0]=1;//为了取模方便,规定数字是从0-n-1的
now=1;
while(m--)
{
scanf("%d",&w);
w%=n;//可能一开始w>n
for(int i=0; i<n; i++)
{
f[now][i]=0;//清空这一轮要用的数组
}
for(int i=0; i<n; i++)
{
if(!f[now^1][i])//这里一定要加一个判断 不加的话TLE 感觉有点玄学
continue;
f[now][(i+w)%n]+=f[now^1][i]*0.5;//now^1就是上一轮的操作
f[now][(i-w+n)%n]+=f[now^1][i]*0.5;
}
now^=1;
}
double ans=0;
for(int i=l; i<=r; i++)
{
ans+=f[now^1][i-1];//因为规定从0开始,所以应该-1
}
printf("%.4f\n",ans);
}
return 0;
}