bzoj2201 彩色圓環
阿新 • • 發佈:2019-02-05
【題意】
略。
【資料範圍】
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; }