《AT_abc321_g Electric Circuit》 解题报告
这个题其实和之前
首先很显然的是拆贡献,寻找每个连通块构成的可能贡献。
期望不好算,我们转成概率乘价值,再转成
我们记
如果一个连通块内部要保证能自己构成一个连通块,那么要满足
那么我们的答案就是
然后我们现在要求一个连通块中连边(保证是恰好一个),这个东西经典
假如
然后我们枚举
而当我们钦定了一个点后,我们的补集就算也是合法的,这样我们也只会计算一次,同时可以保证对于任何都可以计算到,不重不漏。
时间复杂度
点击查看代码
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int N=(1<<17)+10,M=1e5+10,MODD=998244353;
int n,m;
int sr[N],sb[N],R[20],B[20];
LL pw[M],inv[M],f[N];
int main () {
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i) {
int x;
scanf("%d",&x);
++R[x];
}
for(int i=1;i<=m;++i) {
int x;
scanf("%d",&x);
++B[x];
}
pw[0]=inv[0]=inv[1]=1;
for(int i=1;i<=m;++i)
pw[i]=pw[i-1]*i%MODD;
for(int i=2;i<=m;++i)
inv[i]=(MODD-MODD/i)*inv[MODD%i]%MODD;
for(int i=2;i<=m;++i) (inv[i]*=inv[i-1])%=MODD;
LL S=(1<<n)-1;
for(int i=1;i<=S;++i) {
for(int j=1;j<=n;++j) {
if(!(i&(1<<(j-1)))) continue;
sr[i]+=R[j];
sb[i]+=B[j];
}
}
LL ans=0;
for(int i=1;i<=S;++i) {
if(sr[i]!=sb[i]) continue;
f[i]=pw[sr[i]];
int p=(i&(-i));
for(int j=i;j;j=(j-1&i)) {
int t=(i^j);
if(!(j&p)||j==i) continue;
f[i]=(f[i]-f[j]*pw[sr[t]]%MODD+MODD)%MODD;
}
(ans+=f[i]*pw[m-sr[i]]%MODD*inv[m]%MODD)%=MODD;
}
printf("%lld\n",ans);
return 0;
}
本文作者:ddl1no2home
本文链接:https://www.cnblogs.com/ddl1no2home/p/17726113.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步