题解:CF1193A Amusement Park
我不会图计数。
发现题解区没有正着推容斥系数的,那我就来发一个。
首先注意到,一个 DAG 把所有边的方向取反后得到的也是 DAG。所以所有方案要期望要反转的边数为 \(\frac{m}{2}\)。问题转化成将图上一些边反转,形成 DAG 的方案数计数。
考虑 \(f_{S}\) 为将 \(S\) 点集的导出子图定向成 DAG 的方案数。由于 DAG 有优良的性质,即去掉所有入度为 \(0\) 的点后还是 DAG。我们考虑选取一个入度为 \(0\) 的集合。因为入度为 \(0\),因此这个集合中不能有连边,即是一个独立集。
以下的描述中都默认 \(\boldsymbol {T,R}\) 满足独立集的条件。
转移考虑容斥。假设 \(g_T\) 为恰好 \(T\) 中的元素入度为 \(0\) 的方案数,\(h_T\) 为钦定 \(T\) 中的元素入度为 \(0\) 的方案数。不难发现,
又因为在 \(h\) 的定义中,我们只是钦定 \(T\) 中点入度为 \(0\),因此方案数为将剩余点形成 DAG 的方案数,即
又因为 \(g_T\) 的定义是恰好,因此 \(h_T\) 就等于所有满足 \(T \sube R\) 的 \(g_R\) 之和:
至此是一个子集反演的形式,可以得到:
这个时候代回第一个式子,可以得到:
注意在这里由于 \(S\) 是全集,因此还有限制 \(R \sube S\),同时把 \((-1)^{|R|-|T|}\) 变成 \((-1)^{|R|+|T|}\),可以调换求和顺序:
使用二项式定理推论,由于 \(R \not= \varnothing\),有
这样式子就变成
把 \(h_R\) 换回 \(f_{S-R}\),得到
至此,我们说明了容斥系数为 \((-1)^{|R|+1}\)。
那么这道题就做完了。我们可以 \(O(2^nn^2)\) 预处理出每个集合是否为独立集,再用 \(O(3^n)\) 枚举子集进行转移,总复杂度为 \(O(2^nn^2 + 3^n)\)。
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define N 19
using namespace std;
constexpr int MOD=998244353,inv2=499122177;
inline void add(int &x,int y){x+=y,x-=x>=MOD?MOD:0;}
struct Edge{
int u,v;
void read(){scanf("%lld%lld",&u,&v);}
}E[N*N];
int n,m,is[1<<N],f[1<<N],pw[N];
main()
{
scanf("%lld%lld",&n,&m),f[0]=pw[0]=1;
for(int i=1;i<N;i++)pw[i]=(MOD-pw[i-1])%MOD;
for(int i=1;i<=m;i++)E[i].read();
for(int S=0;S<(1<<n);S++)
for(int i=1;i<=m;i++)
if((S>>E[i].u-1)&(S>>E[i].v-1)&1)is[S]=1;
for(int S=1;S<(1<<n);S++)
for(int T=S;T;T=(T-1)&S)
if(!is[T])add(f[S],f[S^T]*pw[__builtin_popcountll(T)+1]%MOD);
printf("%lld\n",f[(1<<n)-1]*m%MOD*inv2%MOD);
return 0;
}

浙公网安备 33010602011771号