我们令
f[n][k]
f
[
n
]
[
k
]
表示n个点,每个点点权在
[0,2k+1)
[
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]
g
[
n
]
[
m
]
[
k
]
表示n个点和m个点之间连一条边,每个点点权在
[0,2k+1)
[
0
,
2
k
+
1
)
间,nm条边里最小的那条边边权的期望,那么上面的期望就是
2k+g[i][n−i][k−1]
2
k
+
g
[
i
]
[
n
−
i
]
[
k
−
1
]
g仍然不能直接dp,还需要一个辅助的状态
我们令
h[n][m][k][l]
h
[
n
]
[
m
]
[
k
]
[
l
]
表示每个点点权在
[0,2k+1)
[
0
,
2
k
+
1
)
间,n个点和m个点之间连的所有边边权都
>=l
>=
l
的概率
转移的时候仍然枚举各自有多少个点在第k位为1,有
dp出h后,有
然后有
复杂度 O(n4m2m) O ( n 4 m 2 m ) ,完全不知道怎么过,但是因为 nm n m 不大,可以把所有 f[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;
}