【gmoj】 【DP】 【期望】 彩色圆环
题目
解题思路
暴力必用dfs跑出各种状态
再求美观值的期望
能跑20分
求一个环其实就是一个特殊的链
尝试将它断开
因为题目求的是一段一段的贡献
将这条链变为一段一段来看
同一段内颜色相同
设f[i][f_len][l_len]表示的是当前段与第一段颜色相同的期望值
而g[i][f_len][[l_len]则是不同颜色
那么认为f_len是第一段的长度
然后l_len是目前最后一段
i是当前位置
那么可以得出转移式
然后我们发现其实可以去除l_len这维
因为要枚举上一段在哪里就可以知道长度
f_len限制的i的起始位置
且f[i,f_len]=f[i-1,f_len-1](f_len≠1)
最终只保留i一维
f[i]表示为从i后的第一段和第一段的颜色相同
g[i]表示的是不同
代码
#include<iostream>
#include<cstdio>
using namespace std;
int n,m;
double p[1010],f[1010],g[1010],ans;
int main()
{
scanf("%d%d",&n,&m);
if (m==1) //特判,只有一种情况
{
printf("%d",n);
return 0;
}
p[0]=1;
for (int i=1;i<=n;i++)
p[i]=p[i-1]/m; //先求出连续i个相同颜色出现的概率
f[0]=1;
for (int i=0;i<n;i++) //枚举last
for (int j=i+1;j<=n;j++) //枚举当前要修改的
{
f[j]+=g[i]*p[j-i]*(j-i); //和的一段相同,和前一段不同,累加前一段的美观值贡献
g[j]+=f[i]*p[j-i]*(j-i)*(m-1)+g[i]*p[j-i]*(j-i)*(m-2); //两种情况,前一段和第一段相同,那么有(m-1)种颜色可选,前一段和第一段不同,那么有(m-2)种可选
}
ans=p[n]*n*m; //所有颜色相同的贡献
for (int i=1;i<n;i++) //枚举第一段长度
ans+=g[n-i]*i*i*p[i]*m; //第一个*i是美观值,第二个i是因为有i个位置可做为起点,*m是有这么多种颜色,去除第一段后还有n-i个点,且不可能和第一段颜色相同所以用的g
printf("%.10f\n",ans);
return 0;
}