Description
给定无向连通图和每条边断开的概率,求期望连通块数量mod998244353
n<=17
Solution
我好菜啊
猜一波复杂度应该是3n的。我们设f[x]表示选取城市状态为x时的答案,g[x]表示选取城市状态为x时形成一个连通块的概率
我们枚举x的子集s转移f,为了不重复我们需要钦定x中编号最小的城市也是在s中编号最小的城市
注意到还需要求出某两个连通块之间所有边都断开的概率,我们令p[x]表示选取城市状态为x时集合内所有边的乘积,于是p[x]/p[s]/p[x-s]就是两个端点分别在两个连通块内的乘积了
g的转移也类似,我们用1减去不连通的概率就行了
然后就要喜闻乐见的卡常了,于是就被卡掉了
Code
#pragma GCC optimize(3)
#include <stdio.h>
#include <string.h>
#include <math.h>
#define rep(i,st,ed) for (register int i=st;i<=ed;++i)
#define lowbit(x) (x&-x)
typedef long long LL;
const int MOD=998244353;
const int N=18;
LL f[1<<N],g[1<<N],p[1<<N];
LL ny[1<<N],rc[N][1<<N];
LL ksm(LL x,LL dep) {
LL ret=1;
for (;dep;dep>>=1) {
(dep&1)?(ret=ret*x%MOD):0;
x=x*x%MOD;
}
return ret;
}
int main(void) {
freopen("fair.in","r",stdin);
// freopen("fair.out","w",stdout);
int n,m; scanf("%d%d",&n,&m);
int lim=(1<<n)-1;
rep(i,0,lim) p[i]=1;
rep(i,1,n) rep(j,0,lim) rc[i][j]=1;
rep(i,1,m) {
int x,y,w; scanf("%d%d%d",&x,&y,&w);
rc[x][1<<(y-1)]=rc[x][1<<(y-1)]*w%MOD;
rc[y][1<<(x-1)]=rc[y][1<<(x-1)]*w%MOD;
}
rep(i,1,n) rep(j,1,lim) {
int x=lowbit(j);
rc[i][j]=rc[i][j^x]*rc[i][x]%MOD;
}
rep(i,0,lim) {
int x=lowbit(i);
p[i]=p[i^x]*rc[1+(int)log2(x)][i^x]%MOD;
}
g[0]=p[0]=ny[0]=1;
rep(i,0,lim) ny[i]=ksm(p[i],MOD-2);
rep(i,1,lim) {
if (i==lowbit(i)) {
f[i]=g[i]=1; continue;
}
int pos=lowbit(i);
g[i]=MOD+1;
for (register int s=(i-1)&i;s;s=(s-1)&i) {
if (lowbit(s)!=pos) continue;
g[i]=(g[i]+MOD-g[s]*p[i]%MOD*ny[i-s]%MOD*ny[s])%MOD;
}
for (register int s=i;s;s=(s-1)&i) {
if (lowbit(s)!=pos) continue;
f[i]=(f[i]+(f[i-s]+1)*g[s]%MOD*p[i]%MOD*ny[i-s]%MOD*ny[s]%MOD)%MOD;
}
}
printf("%lld\n", f[lim]);
return 0;
}