Description
给定一个n个点m条边的无向图
每条边有一个不出现的概率(不为0),求连通块数的期望
无重边自环
答案对998244353取模
n
≤
17
,
m
≤
n
(
n
−
1
)
2
n\leq 17,m\leq {n(n-1)\over 2}
n≤17,m≤2n(n−1)
Solution
考虑单独计算每个连通块的贡献,我们可以枚举一个点集,然后令它自成一个连通块,算出概率,乘上它的所有出边不出现的概率,这就是这个连通块对总期望的贡献,直接累加。
那么现在的问题就是,给定一个点集S,我们需要求出点集S的导出子图(即内部的边+点)连通的概率。
这就是套路了,我们考虑容斥,用1-不连通的概率和。
设
F
[
S
]
F[S]
F[S]为点集S内部连通的概率。
枚举其中标号最小的点i所在的连通块点集T,要求
T
⫋
S
,
i
∈
T
T\subsetneqq S,i\in T
T⫋S,i∈T,这可以采用子集枚举,时间复杂度是
O
(
3
n
)
O(3^n)
O(3n)的
那么现在还需要计算的是
T
T
T和
S
−
T
S-T
S−T之间的边不出现概率之积
如果暴力统计,那么复杂度要多乘个n
然而有个非常妙的方法。
令
G
[
S
]
G[S]
G[S]为点集
S
S
S的导出子图中的边的不出现概率之积
那么
T
T
T和
S
−
T
S-T
S−T之间的边不出现概率之积就是
G
[
S
]
G
[
T
]
×
G
[
S
−
T
]
{G[S]\over G[T]\times G[S-T]}
G[T]×G[S−T]G[S]
因此枚举T,就有 F [ S ] = 1 − ∑ T ⫋ S , l o w b i t ( S ) ∈ T F [ T ] × G [ S ] G [ T ] × G [ S − T ] F[S]=1-\sum\limits_{T\subsetneqq S,lowbit(S)\in T} F[T]\times {G[S]\over G[T]\times G[S-T]} F[S]=1−T⫋S,lowbit(S)∈T∑F[T]×G[T]×G[S−T]G[S]
总的式子就是 A n s = ∑ S F [ S ] ∗ G [ U ] G [ ∁ U S ] × G [ S ] Ans=\sum\limits_{S}F[S]*{G[U]\over G[\complement _U S]\times G[S]} Ans=S∑F[S]∗G[∁US]×G[S]G[U]
总的时间复杂度为 O ( 3 n ) O(3^n) O(3n)
Code
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 18
#define M 131075
#define mo 998244353
#define LL long long
using namespace std;
LL f[M],g[M],a[N][N],ny[M],a1[N*N][2];
int n,m,cf[N];
LL ksm(LL k,LL n)
{
LL s=1;
for(;n;n>>=1,k=k*k%mo) if(n&1) s=s*k%mo;
return s;
}
int main()
{
cin>>n>>m;
fo(i,1,n) fo(j,1,n) a[i][j]=1;
cf[0]=1;
fo(i,1,n) cf[i]=cf[i-1]<<1;
fo(i,1,m)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
a[x][y]=a[y][x]=z;
}
g[0]=1;
fo(i,1,cf[n]-1)
{
g[i]=1;
fo(x,1,n) fo(y,x+1,n) if((cf[x-1]&i)&&(cf[y-1]&i)) g[i]=g[i]*a[x][y]%mo;
ny[i]=ksm(g[i],mo-2);
}
LL ans=0;
ny[0]=1;
fo(i,1,cf[n]-1)
{
f[i]=1;
fod(j,n,1)
{
if(cf[j-1]&i)
{
int l=i^cf[j-1];
for(int r=l&(l-1);r;r=l&(r-1))
{
f[i]=(f[i]-f[r^cf[j-1]]*g[i]%mo*ny[r^cf[j-1]]%mo*ny[l^r]%mo+mo)%mo;
}
if(l!=0) f[i]=(f[i]-f[cf[j-1]]*g[i]%mo*ny[cf[j-1]]%mo*ny[l]%mo+mo)%mo;
break;
}
}
LL s=f[i]*g[cf[n]-1]%mo*ny[i]%mo*ny[(cf[n]-1)^i]%mo;
ans=(ans+s)%mo;
}
printf("%lld\n",ans);
}