dp[i][1/0]表示长度为i的序列,第一个和第二个球颜色不同,第一个和最后一个颜色相同/不同 的期望美观程度
定义很绕,没办法呀…毕竟是个环。
p[i]表示i个连续的球颜色相同的概率
枚举最后一段的长度j来O(n)转移,
dp[i][0]=∑i−1j=1p[j]∗j∗dp[i−j][0]∗(1−2/m)+p[j]∗j∗dp[i−j][1]∗(1−1/m)
dp[i][1]=∑i−1j=1p[j]∗j∗dp[i−j][0]∗1/m
因为是个环,所以我们要钦定第一个球,然后枚举第一个球所在段的长度i 来统计答案,贡献就是
i∗i∗p[i]∗dp[n−i+1]
。如何理解呢?因为是个环,所以覆盖第一个球的长度为i的区间有i个,我们把这个区间缩成一个点,期望长度就是dp[n-i+1]了。特别的,还要加上全是一个颜色的情况,即p[n]*n。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 210
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
int n,m;
double dp[N][2],ans=0,p[N];//p[i]--successive i same color
//dp[i]表示长度为i的序列,第一个和第二个球颜色不同,第一个和最后一个颜色相同(不同)的期望美观程度
int main(){
// freopen("a.in","r",stdin);
n=read();m=read();p[1]=1;dp[1][1]=1;
for(int i=2;i<=n;++i) p[i]=p[i-1]*1.0/m;
for(int i=2;i<=n;++i){
for(int j=1;j<=i;++j){
dp[i][0]+=p[j]*j*dp[i-j][0]*(1-2.0/m)+p[j]*j*dp[i-j][1]*(1-1.0/m);
dp[i][1]+=p[j]*j*dp[i-j][0]*1.0/m;
}
}ans+=p[n]*n;
for(int i=1;i<n;++i) ans+=i*i*p[i]*dp[n-i+1][0];
printf("%.5lf\n",ans);
return 0;
}