P6846 [CEOI 2019] Amusement Park 题解
P6846 [CEOI 2019] Amusement Park 题解
知识点
状压计数 DP,DAG 计数,容斥,FWT。
分析
首先,如果我们可以花 \(c\) 把原图转成一张 DAG,那么就会有另一种 \(m-c\) 的方案。所以答案就变成了 \(\frac{m}{2}\) 倍的无向图定向 DAG 计数。现在考虑 DAG 计数:设 \(f_{S}\) 表示导出子图为 \(S\) 时,DAG 的数量。
有一个最基本的思路,要把 \(S\) 分成两部分,代表的意义是:在确定为 DAG 的第一部分中加入第二部分,生成一个新的 DAG 的方案。发现为了形成 DAG,我们第二部分必须为一个独立集 \(T\),即其中没有可以通过边相连的节点。
我们可以通过 \(O(n2^n)\) 的复杂度预处理出每个集合是否为独立集,记为 \(p_{S}\)(这里定义如果 \(S\) 是独立集,则 \(p_S = 1\))。
那么现在有转移式:(注意 \(T\subset S\) 表示 \(T\) 是 \(S\) 的真子集)
\[f_S = \sum_{T \subseteq S,T \neq \varnothing} f_{S\setminus T} [p_{T}] \\
\]
但是这是一个会重复计数的转移式,所以我们对其进行容斥,现在推导其容斥系数:
设 \(g_T\) 表示限定了导出子图点集 \(S\) 下,选出的第二部分恰好为 \(T\) 时的方案数,那么实际上有:
\[f_S = \sum_{T \subseteq S,T \neq \varnothing} g_{S} \\
g_T = \sum_{T\subseteq V\subseteq S} (-1)^{|V| - |T|} f_{S\setminus V} [p_{V}] \\
\]
所以我们代入:
\[\begin{aligned}
f_S &=
\sum_{T\subseteq S,T \neq \varnothing}
\sum_{T\subseteq V\subseteq S} (-1)^{|V| - |T|} f_{S\setminus V} [p_{V}] \\
f_S &=
\sum_{V\subseteq S,V \neq \varnothing} (-1)^{|V|} f_{S\setminus V} [p_{V}]
\sum_{T\subseteq V,T \neq \varnothing} (-1)^{|T|}
\\
\end{aligned}
\]
众所周知,有二项式定理:(\(|U| = n > 0\))
\[\begin{aligned}
& \because
(1 - 1)^{n} = \sum_{i=0}^{n} {n\choose i} (-1)^i
\Leftrightarrow
\sum_{S\subseteq U}(-1)^{|S|}
\\
& \therefore
\sum_{S\subseteq U}(-1)^{|S|} = 0\\
& \therefore
\sum_{S\subseteq U,S\neq \varnothing}(-1)^{|S|} = -1\\
\end{aligned}
\]
所以上式可以化为:
\[\begin{aligned}
f_S &=
\sum_{V\subseteq S,V \neq \varnothing} (-1)^{|V|+1} f_{S\setminus V} [p_{V}]
\\
\end{aligned}
\]
容斥系数可以在 \(O(2^n)\) 的时间复杂度内算出,总复杂度子集枚举为 \(O(3^n + n2^n)\),如果 FWT 则可以优化到 \(O(n^22^n)\)。
代码
(子集枚举。)
#define Plus_Cat "park"
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define RCL(a,b,c,d) memset(a,b,sizeof(c)*(d))
#define FOR(i,a,b) for(int i(a);i<=(int)(b);++i)
#define DOR(i,a,b) for(int i(a);i>=(int)(b);--i)
#define tomax(a,...) ((a)=max({(a),__VA_ARGS__}))
#define tomin(a,...) ((a)=min({(a),__VA_ARGS__}))
#define EDGE(g,i,x,y) for(int i=(g).h[(x)],y=(g)[(i)].v;~i;y=(g)[(i=(g)[i].nxt)>0?i:0].v)
#define main Main();signed main(){ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);return Main();}signed Main
using namespace std;
constexpr int N(18+10),M(153+10),St((1<<18)+10);
namespace IOEcat {
//Fast IO...
} using namespace IOEcat;
namespace Modular {
//Mod Int...
} using namespace Modular;
bool p[St];
int n,m,U;
int u[M],v[M],c[St],f[St];
signed main() {
#ifdef Plus_Cat
freopen(Plus_Cat ".in","r",stdin),freopen(Plus_Cat ".out","w",stdout);
#endif
I(n,m),U=(1<<n)-1,f[0]=1,c[0]=Mod-1;
FOR(i,1,m)I(u[i],v[i]),p[1<<(u[i]-1)|1<<(v[i]-1)]=1;
FOR(S,1,U)c[S]=(S&1?Mod-c[S^1]:c[S>>1]);
FOR(S,1,U)FOR(i,1,n)if((S&1<<(i-1))&&(p[S]|=p[S^1<<(i-1)]))break;
FOR(S,1,U)for(int T(S); T; T=(T-1)&S)if(!p[T])toadd(f[S],mul(c[T],f[S^T]));
O(mul(f[U],m,Inv2),'\n');
return 0;
}

浙公网安备 33010602011771号