loading

UOJ181 密码锁

题意

给你 \(n\) 个点的完全图,其中有 \(m\) 条边为特殊边。

现在这张完全图需要定向,特殊边定向方向为 \(u_i\rightarrow v_i\) 的概率为 \(\frac{w_i}{10^4}\),普通边两个方向出现的概率均为二分之一。

你需要求出这张图的 SCC 个数的期望乘以 \(10^{4^{n(n-1)}}\) 次方的值。模数 998244353。

\(n\le 38,m\le 19\)

分析

众所周知,竞赛图有一个非常经典的性质:SCC 缩点后形成一条链,链的前部向链的后部连边。

把期望用线性性拆开,拆成“满足所有 \(S\)\(U/S\) 之间的连边均为 \(S\) 指向 \(U/S\) 的非空 \(S\) 个数”,这里 \(U=\{1,2,\cdots,n\}\)。证明也很简单,有且仅有 SCC 链的非空前缀符合条件。

\(n\) 过大,直接枚举 \(S\) 会去世。考虑怎么把 \(m\) 弄到指数上,首先明确一个事实:设 \(S\) 的大小为 \(x\),假设所有边均为普通边,则满足条件的概率为 \(0.5^{x(n-x)}\)。而对于特殊边,考虑将特殊边的概率强制转换成 \(0.5\),然后再乘上额外的 \(\frac{2w_i}{10^4}\) 的贡献即可。这样概率只跟 \(x\) 有关了。

\(f_i\)\(|S|=i\) 且仅考虑特殊边的概率和,则最终答案就是 \(\sum_{i=1}^n f_i\times 0.5^{i(n-i)}\)。考虑到 \(m\) 条边将 \(n\) 个点分成若干个连通块,并且连通块之间相互独立。而不难发现 \(m\) 条边形成的连通块至多只有 \(m+1\) 个点,不妨考虑枚举连通块内划归到 \(S\) 的点集,那么每条边的定向方式以及概率便容易得出。设 \(g_i\) 为当前连通块内 \(|S|=i\) 的概率和,则最后将 \(f,g\) 卷积起来即可。卷积的复杂度根据树上背包结论为均摊 \(O(n^2)\)。总时间复杂度 \(O(2^{m+1}n+n^2)\)

const int maxn=40,mod=998244353,inv2=(mod+1)/2;
int n,m;
struct edge{
	int u,v,zheng,fan;
}b[maxn];
vector<pii>G[maxn];
int ksm(int x,int y){
	int res=1;
	for(;y;y>>=1,x=x*x%mod)if(y&1)res=res*x%mod;
	return res;
}
bool vis[maxn],vise[maxn];
int f[maxn],g[maxn],h[maxn];
inline void adder(int &x,int y){x+=y,x=x>=mod?x-mod:x;}
vector<int>v,e;
void dfs(int x){
	if(vis[x])return;
	vis[x]=1,v.emplace_back(x);
	for(pii _:G[x]){
		int u=_.fi,id=_.se;
		if(!vise[id])e.emplace_back(id),vise[id]=1;
		dfs(u);
	}
}
int id[maxn];
inline void solve_the_problem(){
	n=rd(),m=rd();
	rep(i,1,m){
		int x=rd(),y=rd(),z=rd();
		b[i]=(edge){x,y,z*ksm(5000,mod-2)%mod,(10000-z)*ksm(5000,mod-2)%mod};
		G[x].emplace_back(mp(y,i)),G[y].emplace_back(mp(x,i));
	}
	int tot=0;
	g[0]=1;
	rep(s,1,n)if(!vis[s]){
		v.clear(),e.clear();
		dfs(s);
		rep(i,0,(int)v.size()-1)id[v[i]]=i;
		const int U=(1<<v.size())-1;
		rep(i,0,(int)v.size())f[i]=0;
		rep(S,0,U){
			int P=1;
			for(int i:e){
				int u=b[i].u,v=b[i].v;
				if(((S>>id[u])&1)&&!((S>>id[v])&1))P=P*b[i].zheng%mod;
				if(!((S>>id[u])&1)&&((S>>id[v])&1))P=P*b[i].fan%mod;
			}
			adder(f[popc(S)],P);
		}
		rep(i,0,tot)h[i]=g[i],g[i]=0;
		rep(i,0,tot)rep(j,0,(int)v.size())adder(g[i+j],h[i]*f[j]%mod);
		tot+=v.size();
	}
	int ans=0;
	rep(i,1,n)adder(ans,g[i]*ksm(inv2,i*(n-i))%mod);
	write(ans*ksm(10000,n*(n-1))%mod);
}
posted @ 2025-02-22 10:41  dcytrl  阅读(48)  评论(1)    收藏  举报