bzoj2201 彩色圆环

来源:互联网 发布:回收站清空数据恢复 编辑:程序博客网 时间:2024/04/30 09:32

【题意】

略。

【数据范围】

n<=200,m<=10^9

【思路】

期望DP

[方法一]

f[i][j][k][p]=i个数构成的序列,最长连续前缀=j,最长连续后缀=k,序列两端的字符是(1)否(0)相同

转移时枚举第i个字符与第1个、第(i-1)个字符是否相同即可,O(1)

计算对答案的贡献时,由于首尾两段若颜色相同要接起来,因此特殊地,ans+=f[n][i][j][1]/i/j*(i+j)(i<n,j<n)

[方法二]

f[i][p]=i个数构成的序列,序列两端的字符是(1)否(0)相同

转移时枚举最后一段的长度即可,O(n)

计算答案时,枚举第1个数所在的连续段长度i,由于是环形,故包含第1个数的长度为i的连续段有i种放置方法,故ans+=i*i*f[n-i+1][0]*(1/m)^(i-1)

【时间复杂度】

[方法一]O(n^3)

[方法二]O(n^2)

【方法一】

#include<cstdio>#include<cstring>#include<algorithm>#define N 210#define eps 1e-12using namespace std;int n, m;double f[N][N][N][2], ans;int main(){    scanf("%d%d", &n, &m);    for(int i=1; i<=n; i++)        for(int j=1; j<=n; j++)            for(int k=1; k<=n; k++)f[i][j][k][0]=f[i][j][k][1]=0;    f[1][1][1][1]=1;    for(int i=1; i<=n-1; i++)        for(int j=1; j<=i; j++)            for(int k=1; k<=i; k++){                if(f[i][j][k][0]>0){                    if(j==i&&k==i)f[i+1][j+1][k+1][0]+=f[i][j][k][0]/i*(i+1)*1.0/m;                    else f[i+1][j][k+1][0]+=f[i][j][k][0]/k*(k+1)*1.0/m;                    f[i+1][j][1][0]+=f[i][j][k][0]*(1-2.0/m);                    f[i+1][j][1][1]+=f[i][j][k][0]*1.0/m;                }                if(f[i][j][k][1]>0){                    if(j==i&&k==i)f[i+1][j+1][k+1][1]+=f[i][j][k][1]/i*(i+1)*1.0/m;                    else f[i+1][j][k+1][1]+=f[i][j][k][1]/k*(k+1)*1.0/m;                    f[i+1][j][1][0]+=f[i][j][k][1]*(1-1.0/m);                }            }    ans=0;    for(int i=1; i<=n; i++)        for(int j=1; j<=n; j++){            if(f[n][i][j][0]>0)ans+=f[n][i][j][0];            if(f[n][i][j][1]>0){                if(i==n&&j==n)ans+=f[n][i][j][1];                else ans+=f[n][i][j][1]/i/j*(i+j);            }        }    printf("%.5f", ans);    return 0;}
【方法二】

#include<cstdio>#include<cstring>#include<algorithm>#define N 210using namespace std;int n, m;double f[N][2], p[N], ans;int main(){    scanf("%d%d", &n, &m);    for(int i=1; i<=n; i++)f[i][0]=f[i][1]=0; f[1][1]=1;    p[0]=1; for(int i=1; i<=n; i++)p[i]=p[i-1]*1.0/m;    for(int i=2; i<=n; i++)        for(int j=1; j<=i-1; j++){            f[i][0]+=f[j][0]*(i-j)*p[i-j-1]*(1-2.0/m)+f[j][1]*(i-j)*p[i-j-1]*(1-1.0/m);            f[i][1]+=f[j][0]*(i-j)*p[i-j];        }    ans=p[n-1]*n;    for(int i=1; i<=n-1; i++)ans+=i*i*f[n-i+1][0]*p[i-1];    printf("%.5f", ans);    return 0;}


0 0