BZOJ4770: 图样

我们令 f [ n ] [ k ] 表示n个点,每个点点权在 [ 0 , 2 k + 1 ) ,MST边权和的期望
转移的时候,我们枚举有i个点第k位为1,n-i个点第k位为0,则最后的MST一定是i个点和n-i个点之间连一条边,剩下i个点,n-i个点个组成一棵生成树,而这个可以被划分成子问题
现在的问题在于i个点和n-i个点之间连一条边,这条边一定是i(n-i)条边里面最小的,那么这条边边权的期望怎么算
我们令 g [ n ] [ m ] [ k ] 表示n个点和m个点之间连一条边,每个点点权在 [ 0 , 2 k + 1 ) 间,nm条边里最小的那条边边权的期望,那么上面的期望就是 2 k + g [ i ] [ n i ] [ k 1 ]

g仍然不能直接dp,还需要一个辅助的状态
我们令 h [ n ] [ m ] [ k ] [ l ] 表示每个点点权在 [ 0 , 2 k + 1 ) 间,n个点和m个点之间连的所有边边权都 >= l 的概率
转移的时候仍然枚举各自有多少个点在第k位为1,有

h [ n ] [ m ] [ k ] [ l ] = x , y C n x C m y 2 n + m h [ x ] [ y ] [ k 1 ] [ l ] h [ n x ] [ m y ] [ k 1 ] [ l ] h [ x ] [ m y ] [ k 1 ] [ l 2 k ] h [ n x ] [ y ] [ k 1 ] [ l 2 k ]
(边界要注意一下)

dp出h后,有

g [ n ] [ m ] [ k ] = l > 0 h [ n ] [ m ] [ k ] [ l ]

然后有

f [ n ] [ k ] = i C n i 2 n ( f [ i ] [ k 1 ] + f [ n i ] [ k 1 ] + ( g [ i ] [ n i ] [ k 1 ] + 2 k ) [ i ( n i ) > 0 ] )

复杂度 O ( n 4 m 2 m ) ,完全不知道怎么过,但是因为 n m 不大,可以把所有 f [ n ] [ m ] 打个表预处理出来

code(用来打表的程序):

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

const int maxn = 55;
const int maxk = 8;
const int mod  = 258280327;
inline void add(int &a,const int &b){a+=b;if(a>=mod)a-=mod;}

int pw(int x,int k)
{
    int re=1;
    for(;k;k>>=1,x=(ll)x*x%mod) if(k&1)
        re=(ll)re*x%mod;
    return re;
}
int inv(int x){ return pw(x,mod-2); }

int n,m;
int C[maxn][maxn],inv2[maxn];
int f[maxn][maxk],g[maxn][maxn][maxk],h[maxn][maxn][maxk][1<<maxk];

void dph()
{
    for(int i=1;i<=n;i++) for(int j=1;i+j<=n;j++)
        h[i][j][0][1]=inv2[i+j-1];
    for(int k=1;k<m;k++)
    {
        for(int i=1;i<=n;i++) for(int j=1;i+j<=n;j++)
        {
            for(int l=1;l<(1<<k+1);l++)
            {
                for(int x=0;x<=i;x++) for(int y=0;y<=j;y++)
                {
                    int p=(ll)C[i][x]*C[j][y]%mod;
                    if(x&&y) p=(ll)p*h[x][y][k-1][l]%mod;
                    if(i-x&&j-y) p=(ll)p*h[i-x][j-y][k-1][l]%mod;
                    if(x&&j-y&&(1<<k)<l) p=(ll)p*h[x][j-y][k-1][l-(1<<k)]%mod;
                    if(i-x&&y&&(1<<k)<l) p=(ll)p*h[i-x][y][k-1][l-(1<<k)]%mod;
                    add(h[i][j][k][l],p);
                }
                h[i][j][k][l]=(ll)h[i][j][k][l]*inv2[i+j]%mod;
            }
        }
    }
}
void dpg()
{
    for(int i=1;i<=n;i++) for(int j=1;i+j<=n;j++) for(int k=0;k<m;k++)
        for(int l=1;l<(1<<k+1);l++) add(g[i][j][k],h[i][j][k][l]);
}
void dpf()
{
    for(int i=1;i<=n;i++) 
    {
        for(int j=0;j<=i;j++)
        {
            int p=C[i][j],c=0;
            if(j&&i-j) c=1;
            add(f[i][0],p*c);
        }
        f[i][0]=(ll)f[i][0]*inv2[i]%mod;
    }
    for(int k=1;k<m;k++)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<=i;j++)
            {
                int p=C[i][j],c=0;
                if(j&&i-j) c=g[j][i-j][k-1]+(1<<k);
                if(j) add(c,f[j][k-1]);
                if(i-j) add(c,f[i-j][k-1]);
                add(f[i][k],(ll)p*c%mod);
            }
            f[i][k]=(ll)f[i][k]*inv2[i]%mod;
        }
    }
}

int main()
{
    freopen("tmp.in","r",stdin);
    freopen("tmp.out","w",stdout);

    //scanf("%d%d",&n,&m);
    n=50; m=8;

    C[0][0]=1;
    for(int i=1;i<=n;i++)
    {
        C[i][0]=1;
        for(int j=1;j<=i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
    }
    inv2[0]=1,inv2[1]=(mod+1)>>1;
    for(int i=2;i<=n;i++) inv2[i]=(ll)inv2[i-1]*inv2[1]%mod;

    dph();
    dpg();
    dpf();

    for(int i=1;i<=n;i++) for(int j=0;j<m;j++) printf("%d,",f[i][j]);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/l_0_forever_lf/article/details/80251677