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;
}

posted @ 2025-05-23 18:52  Add_Catalyst  阅读(14)  评论(0)    收藏  举报