概率DP裸题 n*m暴力可过 见代码一
但是存在优化的方法 可以发现w很小 也就是步数的种类很小 又因为只要各种步子迈的次数一样 最后到达每个点的概率都是一样的 就像1-2和-2+1结果一样是一个道理 所以对步数排序 每种步子分别处理
在暴力DP的过程中 有如下转移式子 dp[cur^1][(i-w+n)%n]+=0.5*dp[cur][i]; dp[cur^1][(i+w)%n]+=0.5*dp[cur][i]; 这个式子代表在第i步到第i+1步时的转移状态 其实可以发现 如果如果从第i步转移到第k步时 也存在类似的递推关系 即只要知道走完k步时到达每一点的概率即可 然后用类似快速幂的方法优化
一
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e2+10;
double dp[2][maxn];
int n,m,l,r;
int main()
{
double ans;
int i,cur,w;
while(scanf("%d%d%d%d",&n,&m,&l,&r)!=EOF){
if(n==0&&m==0&&l==0&&r==0) break;
l--,r--;
for(i=0;i<n;i++){
dp[0][i]=dp[1][i]=0.0;
}
dp[0][0]=1.0;
cur=0;
while(m--){
scanf("%d",&w);
for(i=0;i<n;i++){
if(dp[cur][i]>0.0){
dp[cur^1][(i-w+n)%n]+=0.5*dp[cur][i];
dp[cur^1][(i+w)%n]+=0.5*dp[cur][i];
dp[cur][i]=0.0;
}
}
cur^=1;
}
ans=0.0;
for(i=l;i<=r;i++){
ans+=dp[cur][i];
}
printf("%.4f\n",ans);
}
return 0;
}
二
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
double ans[210],mat[210];
int book[110];
int n,m,l,r;
void mul(double *a,double *b)
{
double c[210];
int i,j;
memset(c,0,sizeof(c));
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
c[i]+=a[j]*b[j>=i?(j-i):(n+j-i)];
}
}
memcpy(a,c,sizeof(c));
return;
}
int main()
{
double sum;
int w,t,i,j;
while(scanf("%d%d%d%d",&n,&m,&l,&r)!=EOF)
{
if(n==0&&m==0&&l==0&&r==0) break;
memset(book,0,sizeof(book));
while(m--)
{
scanf("%d",&w);
book[w]++;
}
memset(ans,0,sizeof(ans));
ans[0]=1.0;
for(i=1;i<=100;i++)
{
if(book[i]>0)
{
t=book[i];
memset(mat,0,sizeof(mat));
mat[i%n]+=0.5,mat[(-i%n+n)%n]+=0.5;
while(t>0)
{
if(t%2)
{
mul(ans,mat);
}
mul(mat,mat);
t/=2;
}
}
}
sum=0;
for(i=l-1;i<=r-1;i++)
{
sum+=ans[i];
}
printf("%.4f\n",sum);
}
return 0;
}