# [UOJ#348]-[WC2018]州区划分-FMT

luogu什么情况= =
me就交了三次，还都被卡常了

luogu差评*1

## 题目

UOJ#348传送门

### 解法

（还记得当时，怎么都过不了样例的绝望hhhh）

### 下面是自带大常数的代码

#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;

const int P = 998244353 ;
int N , M , px , sumw[1<<21] ;
int Fstate , acce[25] , sum[22][1<<21] , dp[22][1<<21] ;
short popcnt[1<<21] ;
map<int,int> bi ;

long long s_pow( long long x , int b ){
long long rt = 1 ;
while( b ){
if( b&1 ) rt = rt * x %P ;
x = x * x %P , b >>= 1 ;
} return rt ;
}

int vis ;
void dfs( int S , int u ){
vis |= ( 1 << u ) ;
for( int v = acce[u] ; v ; v -= v&-v )
if( ( S & (v&-v) ) && !( vis & (v&-v) ) ) dfs( S , bi[v&-v] ) ;
}

void check( int S ){
vis = 0 ;
int ok = 0 ;
for( int i = 0 ; i < N ; i ++ ){
if( !( S & ( 1 << i ) ) ) continue ;
if( popcnt[ S&acce[i] ] & 1 ){ ok = 1 ; break ; }
} if( !ok ) dfs( S , bi[S&-S] ) ;
if( ok || popcnt[vis] != popcnt[S] ){
if( px == 0 ) sum[popcnt[S]][S] = 1 ;
else if( px == 1 ) sum[popcnt[S]][S] = sumw[S] ;
else sum[popcnt[S]][S] = sumw[S] * sumw[S] ;
}
}

void preWork(){
Fstate = ( 1 << N ) - 1 ;
for( int i = 0 ; i <= N ; i ++ ) bi[1<<i] = i ;
for( int i = 1 ; i <= Fstate ; i ++ ){
popcnt[i] = popcnt[ i^(i&-i) ] + 1 ;
sumw[i] = sumw[ i^(i&-i) ] + sumw[i&-i] ;
} for( int i = 1 ; i <= Fstate ; i ++ ) check( i ) ;
}

void FMT( int *a ){
for( int i = 0 ; i < N ; i ++ )
for( int j = 0 ; j <= Fstate ; j ++ )
if( j&(1<<i) ) a[j] = ( a[j] + a[j^(1<<i)] )%P ;
}

void IFMT( int *a ){
for( int i = 0 ; i < N ; i ++ )
for( int j = 0 ; j <= Fstate ; j ++ )
if( j&(1<<i) ) a[j] = ( a[j] - a[j^(1<<i)] )%P ;
}

void solve(){
for( int i = 1 ; i <= N ; i ++ ) FMT( sum[i] ) ;
for( int i = 0 ; i <= Fstate ; i ++ ) dp[0][i] = 1 ;

for( int i = 1 ; i <= N ; i ++ ){
int *g = dp[i] ;
for( int j = 0 ; j < i ; j ++ ){
int *f = dp[j] , *q = sum[i-j] ;
for( int r = 0 ; r <= Fstate ; r ++ )
g[r] = ( g[r] + 1LL * f[r] * q[r] )%P ;
} IFMT( g ) ;
if( px ) for( int r = 0 ; r <= Fstate ; r ++ ){
if( popcnt[r] != i ) continue ;
long long tmp = s_pow( sumw[r] , P - 2 ) ;
if( px == 2 ) tmp = tmp * tmp %P ;
g[r] = tmp * g[r] %P ;
} if( i != N ) FMT( g ) ;
} printf( "%d" , ( dp[N][Fstate] + P )%P ) ;
}

int main(){
scanf( "%d%d%d" , &N , &M , &px ) ;
for( int i = 1 , u , v ; i <= M ; i ++ ){
scanf( "%d%d" , &u , &v ) ;
u -- , v -- ;
acce[u] |= ( 1 << v ) ;
acce[v] |= ( 1 << u ) ;
} for( int i = 0 ; i < N ; i ++ )
scanf( "%d" , &sumw[1<<i] ) ;
preWork() ; solve() ;
}