BZOJ 2685: Sgu385 highlander

时间:2023-03-08 19:48:36
BZOJ 2685: Sgu385 highlander

Sol

期望DP.

\(f[i][j][k]\) 表示已经确定了 \(i\) 个点, 最大环大小为 \(j\) ,个数为 \(k\) 的方案数.

转移非常复杂,因为细节特别多.

\(f[i][j][1]=\frac{A_{j}^{n}}{j},i=j,k=1\)

\(f[i][j][1]=\frac{A_{j}^{n-i+j}}{j} \sum_{l=1}^{j} g[i][j],i>j,k=1\)  这个地方的 \(g[i][j]\) 我写的跟论文里的不太一样...不知道是论文里写错了还是我理解错了.

\(f[i][j][k]=f[i-j][j][k-1]\frac{A_{j}^{n-i+j}}{jk},i>j,1<k*j<=i\) 因为要考虑几个环的顺序,所以要除去一个 \(k\) 的排列.

其中 \(g[i][j]=\sum_{l=2}^{\frac{i}{j}} f[i][j][l] \)

\(n<=100\) 没人打表?打表Rank1系列.

Update:因为期望总是小于 \(100\) ,而double类型以对数方式储存,所以可以保证答案的正确性.

Code

/**************************************************************
Problem: 2685
User: BeiYu
Language: C++
Result: Accepted
Time:392 ms
Memory:10508 kb
****************************************************************/ #include<cstdio>
#include<iostream>
using namespace std; const int N = 105; int n;
double fac[N],A[N][N];
double f[N][N][N],g[N][N],d[N];
double ans; int main(){
// freopen("in.in","r",stdin);
scanf("%d",&n); fac[0]=1;for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i;
for(int i=1;i<=n;i++) for(int j=1;j<=i;j++) A[i][j]=fac[i]/fac[i-j];
d[1]=0,d[2]=1;for(int i=3;i<=n;i++) d[i]=(i-1)*(d[i-1]+d[i-2]); for(int i=1;i<=n;i++){
for(int j=2;j<=i;j++){
if(i==j) f[i][j][1]=A[n][j]/j;
else{
for(int l=2;l<j;l++) f[i][j][1]+=g[i-j][l];
f[i][j][1]*=A[n-i+j][j]/j;
}
for(int k=2;k*j<=i;k++) f[i][j][k]=f[i-j][j][k-1]*A[n-i+j][j]/j/k;
}
for(int j=2;j<=i;j++) for(int k=1;k*j<=i;k++) g[i][j]+=f[i][j][k];
} for(int j=2;j<=n;j++) for(int k=1;k*j<=n;k++) ans+=j*k*f[n][j][k];
ans/=d[n];
printf("%.14lf\n",ans);
return 0;
}