题目
点这里看题目。
分析
手玩容易发现 good graph 的第二条要求等价于 (G') 是二分图。
说明:
设 (x_u) 表示某种方案中 (u) 是否被操作。
那么有 (|E'|) 条方程。对于 ((u,v)in E'),方程的形式为 (x_uoplus x_v=1)。
取出任意的相邻两条边,比如 ((u,v),(v,w)),将两条方程异或起来得到 (x_u=x_w)。
那么 (x) 对应了一种黑白染色方案,而当且仅当 (G') 是二分图的时候,才会存在合法的 (x)。
考虑二分图比较好用的性质:有且仅有二分图可以被黑白染色。那么限制变成:
- (G') 连通;
- (G') 可以被黑白染色;
注意到“可以被黑白染色”这条限制明显比“连通”难处理得多,因此我们优先处理掉第二条限制。
设 (G[S]) 为点集 (S) 在 (G) 上的导出子图,(G[S]=(S,E[S]))。我们可以设 (f_S) 为所有 (G'=(S,E'),E'subseteq E[S]) 的黑白染色方案的数量之和。这个很容易计算,我们只需要枚举哪些染白、哪些染黑,则边一定从跨黑白的边之中选出。
(f) 中的图有些是不连通的,我们需要再将它们处理掉。这很容易,我们只需要设 (g_S) 为所有连通的 (G') 的黑白染色方案的数量之和即可,而 (g) 也可以使用 DP 简单地计算。我们可以钦定元素 (kin S),则有:
[g_S=f_S-sum_{kin Tsubsetneq S}g_T imes f_{Ssetminus T}
]
注意到,连通的二分图只有两种黑白染色方案,那么答案即为 (frac{1}{2}g_{U})。
小结:
- 限制较多的时候,一定要注意哪些限制比较难以处理,难以处理的限制一般会通过枚举或优先保证的方式来解决;
- 本题中,我们没有选择直接对图计数,而是对图染色方案数计数,最终利用性质可以简单地推出答案。很多时候不一定可以方便地直接算出答案,我们最好是计算某些易于计算的量再较快地推出答案。
代码
#include <cstdio>
#define rep( i, a, b ) for( int i = (a) ; i <= (b) ; i ++ )
#define per( i, a, b ) for( int i = (a) ; i >= (b) ; i -- )
const int mod = 998244353;
const int MAXN = 20, MAXM = 17 * 16 + 5, MAXS = ( 1 << 17 ) + 5;
int grp[MAXS];
int f[MAXS], g[MAXS];
int pw[MAXM];
int N, M;
inline int Mul( int x, int v ) { return 1ll * x * v % mod; }
inline int Sub( int x, int v ) { return ( x -= v ) < 0 ? x + mod : x; }
inline int Add( int x, int v ) { return ( x += v ) >= mod ? x - mod : x; }
int main()
{
scanf( "%d %d", &N, &M );
rep( i, 1, M )
{
int a, b;
scanf( "%d %d", &a, &b ), a --, b --;
for( int S = 0 ; S < ( 1 << N ) ; S ++ )
if( ( S >> a & 1 ) && ( S >> b & 1 ) )
grp[S] ++;
}
pw[0] = 1; rep( i, 1, M ) pw[i] = Mul( pw[i - 1], 2 );
for( int S = 0 ; S < ( 1 << N ) ; S ++ )
{
g[S] = 1;
for( int T = S ; T ; T = ( T - 1 ) & S )
g[S] = Add( g[S], pw[grp[S] - grp[T] - grp[S ^ T]] );
}
f[0] = 1;
for( int S = 1 ; S < ( 1 << N ) ; S ++ )
{
int low = S & ( - S ); f[S] = g[S];
for( int T = ( S - 1 ) & S ; T ; T = ( T - 1 ) & S )
{
if( ! ( T & low ) ) continue;
f[S] = Sub( f[S], Mul( f[T], g[S ^ T] ) );
}
}
printf( "%d
", Mul( f[( 1 << N ) - 1], ( mod + 1 ) >> 1 ) );
return 0;
}