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;
}

  

 

posted @ 2016-09-11 20:44  北北北北屿  阅读(423)  评论(0编辑  收藏  举报