1. 程式人生 > >bzoj2201 彩色圓環

bzoj2201 彩色圓環

【題意】

略。

【資料範圍】

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-12
using 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 210
using 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;
}