题目
分析:
老规矩,遇到期望要准备好随时投降。。。
大致想到了按位处理,然后分别下去搜索,再用组合数加加减减一下。。。
但是两个连通块之间连边的期望怎么算呢?
很好,投降。。。
下来看题解。。。
果然是记搜。。
首先我们设F(n,m)表示n个点取 [ 0 , 2^m )的值时所有最小生成树代价之和
那么Ans=F(n,m) / 2^(n*m)
再设G(S,T,m)表示一部分点集大小为S,另一部分大小为T,点权取值在[ 0 , 2^m )之间后,所有情况最小边权值的总和
于是F(n,m)可以记搜:
F(n,m)=
sigma(i=1...n) C(n,i)(选哪些点) * (
F( i , m-1 ) * 2^( (n-i) * (m-1) )(一部分向下搜索再乘方案数) +
F( n-i , m-1 ) * 2^( i * (m-1) )(另一部分) +
G( i , n-i , m-1)(中间连边) +
2 ^ (m-1) * 2 ^ ( n * (m-1) )(必须花费的代价乘上方案数) )
然后我们来求G:
我们叒设一个函数P(S,T,m,K)表示点集S,T,取值[ 0 , 2^m )时,边权最小值大于等于K的情况数
G(S,T,m)可以巧妙地化为sigma(i=1...(2^m-1))P(S,T,m,i)
奥妙重重,可以脑补一下,跟前缀和差不多的感觉
然后P就很好求了,暴力地将S和T继续按01位分割下去,某一位全部都不分割时统计入答案
三重记搜,式子还这么难
神仙题Orz
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #define maxn 55 #define maxm 9 #define MOD 258280327 using namespace std; inline long long getint() { long long num=0,flag=1;char c; while((c=getchar())<‘0‘||c>‘9‘)if(c==‘-‘)flag=-1; while(c>=‘0‘&&c<=‘9‘)num=num*10+c-48,c=getchar(); return num*flag; } int n,m; long long C[maxn][maxn],F[maxn][maxm],G[maxn][maxn][maxm],P[maxn][maxn][maxm][1<<maxm],pw[maxn*maxm]; inline long long ksm(long long num,long long k) { long long ret=1; for(;k;k>>=1,num=num*num%MOD)if(k&1)ret=ret*num%MOD; return ret; } inline long long getP(int S,int T,int M,int K) { if(S>T)swap(S,T); if(!S||K<=0)return pw[(S+T)*M]; if(K>=(1<<M))return 0; if(~P[S][T][M][K])return P[S][T][M][K]; long long tmp=0; for(int i=0;i<=S;i++)for(int j=0;j<=T;j++) if((i==0&&j==T)||(i==S&&j==0))tmp=(tmp+getP(S,T,M-1,K-(1<<(M-1))))%MOD; else tmp=(tmp+getP(i,j,M-1,K)*getP(S-i,T-j,M-1,K)%MOD*C[S][i]%MOD*C[T][j]%MOD)%MOD; return P[S][T][M][K]=tmp; } inline long long getG(int S,int T,int M) { if(!M)return 0; if(S>T)swap(S,T); if(~G[S][T][M])return G[S][T][M]; long long tmp=0; for(int i=1;i<(1<<M);i++) tmp=(tmp+getP(S,T,M,i))%MOD; return G[S][T][M]=tmp; } inline long long getF(int N,int M) { if(!M||N<2)return 0; if(~F[N][M])return F[N][M]; long long tmp=2*getF(N,M-1)%MOD; for(int i=1;i<N;i++) tmp=(tmp+C[N][i]*(getF(i,M-1)*pw[(N-i)*(M-1)]%MOD+getF(N-i,M-1)*pw[i*(M-1)]%MOD+getG(i,N-i,M-1)+(1<<(M-1))*pw[N*(M-1)]%MOD))%MOD; return F[N][M]=tmp; } int main() { n=getint(),m=getint(); pw[0]=1;for(int i=1;i<=n*m;i++)pw[i]=pw[i-1]*2%MOD; for(int i=0;i<=n;i++) { C[i][0]=C[i][i]=1; for(int j=1;j<i;j++)C[i][j]=(C[i-1][j-1]+C[i-1][j])%MOD; } memset(F,-1,sizeof F),memset(G,-1,sizeof G),memset(P,-1,sizeof P); printf("%lld\n",getF(n,m)*ksm(pw[n*m],MOD-2)%MOD); }
原文地址:https://www.cnblogs.com/Darknesses/p/12149853.html
时间: 2024-11-11 04:59:45