「ARC105F」Lights Out on Connected Graph
阿新 • • 發佈:2021-08-10
題目
點這裡看題目。
分析
手玩容易發現 good graph 的第二條要求等價於 \(G'\) 是二分圖。
說明:
設 \(x_u\) 表示某種方案中 \(u\) 是否被操作。
那麼有 \(|E'|\) 條方程。對於 \((u,v)\in E'\),方程的形式為 \(x_u\oplus 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\)
注意到,連通的二分圖只有兩種黑白染色方案,那麼答案即為 \(\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\n", Mul( f[( 1 << N ) - 1], ( mod + 1 ) >> 1 ) );
return 0;
}