AT_abc321_g [ABC321G] Electric Circuit 题解
前言
没怎么写过概率、期望的题,做不了一点。并且感觉其他题解写的有点简略了,有点看不懂,结合自己的理解记录一下。
正文
0x00 题目分析
简述一下题意:给定一个
发现这个题每一个黑点连接哪些蓝点和红点是不重要的,只需要关注每一个黑点连接了几个蓝点和红点就可以了,那么后续的讨论本质是对黑点的讨论,并且黑点的数量十分少。不妨记
0x01 拆分贡献
发现这个题是求期望,那么要想到期望的性,当然比较重要的就是期望的线性性,也正是这个题的入手点。相当于是把一个整体计算性的问题,拆分成了一个一个小的局部问题计算贡献,而把大问题转化为小问题,往往就是突破题目的关键。
具体来说就是先把分母算完,分母很多时候更好就算,对于拆分出来的一个小局部问题,对分母的贡献就是,这个局部的答案乘上包含这个局部的情况数量,最后除一下总的情况数量就是分母,就可以了。
不妨先考虑每一个黑点子集
记整数是
0x02 算方案数
先看看这个子集可能形成恰好一个联通分量的方案数有多少,记这个值是
可以理解为,
0x03 算贡献
算了方案数还没算贡献呢,其实这里和算
但是这里不会算重,因为算的时期望的贡献,对于每个联通分量他就会贡献
0x04 代码实现
写起来很简单,跑得也很快,时间复杂度
AC CODE
#include<bits/stdc++.h>
// #define ONLINE_JUDGE
#define INPUT_DATA_TYPE int
#define OUTPUT_DATA_TYPE int
INPUT_DATA_TYPE read(){register INPUT_DATA_TYPE x=0;register char f=0,c=getchar();while(c<'0'||'9'<c)f=(c=='-'),c=getchar();while('0'<=c&&c<='9')x=(x<<3)+(x<<1)+(c&15),c=getchar();return f?-x:x;}void print(OUTPUT_DATA_TYPE x){register char s[20];register int i=0;if(x<0){x=-x;putchar('-');}if(x==0){putchar('0');return;}while(x){s[i++]=x%10;x/=10;}while(i){putchar(s[--i]+'0');}return;}
#define INV_DATA_TYPE long long
INV_DATA_TYPE exgcd(INV_DATA_TYPE a,INV_DATA_TYPE b,INV_DATA_TYPE&x,INV_DATA_TYPE&y){if(!b){x=1;y=0;return a;}INV_DATA_TYPE d=exgcd(b,a%b,y,x);y-=a/b*x;return d;}INV_DATA_TYPE inv(INV_DATA_TYPE n,INV_DATA_TYPE p){INV_DATA_TYPE x,y;exgcd(n,p,x,y);x%=p;return x>=0?x:x+p;}
const long long mod=998244353;
int rsiz[1<<17],bsiz[1<<17],rdeg[17],bdeg[17];
long long fact[100010],dp[1<<17];
int lowbit(int x){return x&-x;}
int main(){
#ifndef ONLINE_JUDGE
freopen("name.in", "r", stdin);
freopen("name.out", "w", stdout);
#endif
register int i,s,maxs,subs;
register long long res=0;
int n=read();
int m=read();
fact[0]=1;
for(i=1;i<=m;++i) fact[i]=fact[i-1]*i%mod;
for(i=0;i<m;++i) ++rdeg[read()-1];
for(i=0;i<m;++i) ++bdeg[read()-1];
maxs=1<<n;
for(s=1;s<maxs;++s){
for(i=0;i<n;++i)
if((s>>i)&1)
rsiz[s]+=rdeg[i],
bsiz[s]+=bdeg[i];
if(rsiz[s]!=bsiz[s]) continue;
dp[s]=fact[rsiz[s]];
for(subs=s&(s-1);subs;subs=(subs-1)&s){
if(lowbit(subs)!=lowbit(s)||rsiz[subs]!=bsiz[subs]) continue;
(dp[s]+=mod-dp[subs]*fact[rsiz[s]-rsiz[subs]]%mod)%=mod;
}
(res+=dp[s]*fact[m-rsiz[s]])%=mod;
}
print(res*inv(fact[m],mod)%mod);
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
总结
抓住概率和期望的性质,对问题进行拆分贡献,可以尝试选择用总的方案数减去不合法方案数,这样的结构对问题进一次拆分简化问题。