密码锁
Description
Data Constraint
1
≤
Solution
由于定向后原图是一个竞赛图,进行强连通分量缩点后,一定是一个拓扑序唯一的 DAG ,此 DAG 的点数的期望值就是答案。
不难发现,此
DAG
可以分成两个集合
S
,
于是我们可以将答案写成
当
m
=
那当
m
不等于
对于一个弱连通分量
K
,我们用
对于一个弱连通分量我们可以求出一个
f
,
再设一个
ansi
表示做到当前弱连通分量时总共有
i
个点属于
我们每做一个弱连通分量就将得到的
f
和
最后答案就为
Ans=1+∑n−1i=1ansi12i(n−i)
可以证明时间复杂度的上限为
O(2m+1n+n2)
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,j,l) for(int i=j;i<=l;++i)
#define fd(i,j,l) for(int i=j;i>=l;--i)
using namespace std;
typedef long long ll;
const ll N=49,M=2e6,mo=998244353;
ll f[N],g[N];
int x[N],y[N],c[N],d[N],m2[N];
int sta[N],fa[N];
int n,m,i,o,p;
inline ll ksm(ll o,ll t)
{
ll y=1;
for(;t;t>>=1,o=o*o%mo)
if(t&1)y=y*o%mo;
return y;
}
int gf(int a)
{return fa[a]==a?a:fa[a]=gf(fa[a]);}
inline int bits(int o)
{return (!o)?0:(o&1)+bits(o>>1);}
int main()
{
freopen("random.in","r",stdin);
freopen("random.out","w",stdout);
cin>>n>>m;
fo(i,1,n)fa[i]=i;
fo(i,1,m){
scanf("%d%d%d",&x[i],&y[i],&c[i]);
if(gf(x[i])!=gf(y[i])){
fa[fa[x[i]]]=fa[y[i]];
}
}
m2[1]=1;
fo(i,2,n+1)m2[i]=m2[i-1]<<1;
f[0]=1; ll ny=ksm(10000,mo-2);
fo(i,1,n)if(fa[i]){
int v=0;
fo(l,0,n)g[l]=0;
fo(l,1,n)if(gf(i)==gf(l))d[++v]=l;
fo(l,1,v)fa[d[l]]=-1;
fo(l,0,m2[v+1]-1){
ll tot=1; int tj=0;
fo(j,1,v)sta[d[j]]=(l&m2[j])>0;
fo(j,1,m)if(fa[x[j]]+fa[y[j]]==-2){
if(sta[x[j]]==1&&sta[y[j]]==0)tot=tot*2*c[j]%mo*ny%mo;
else if(sta[x[j]]==0&&sta[y[j]]==1)tot=tot*2*(10000-c[j])%mo*ny%mo;
}
int gs=bits(l);
g[gs]=(g[gs]+tot)%mo;
}
fd(l,n,0){
ll op=0;
fo(j,0,l)op=(op+f[j]*g[l-j])%mo;
f[l]=op;
}
fo(l,1,v)fa[d[l]]=0;
}
ll ans=1;
fo(i,1,n-1)ans=(ans+f[i]*ksm((mo+1)>>1,i*(n-i)))%mo;
ans=ans*ksm(10000,n*(n-1))%mo;
cout<<ans;
}
本文针对UOJ平台上的密码锁问题进行了深入分析,提出了一种基于强连通分量缩点后的拓扑排序唯一DAG的解决方案。文章详细介绍了如何通过概率计算来确定合法划分方案的数量,并给出了具体的算法实现。

8983

被折叠的 条评论
为什么被折叠?



