[WC2018]州区划分(FWT_OR卷积)
problem
洛谷鏈接
solution
顯然題目指向:存在歐拉回路的州劃分是不合法的。
當(dāng)且僅當(dāng)這個(gè)州是 聯(lián)通 的且 內(nèi)部沒(méi)有奇數(shù)度數(shù)的點(diǎn) 時(shí),這個(gè)州不合法。
因?yàn)?nnn 非常小,我們可以枚舉每一種州劃分方案,判斷是否合法,順便記錄每個(gè)劃分方案的貢獻(xiàn)。
設(shè) f(s):f(s):f(s): 當(dāng)前劃分集合為 sss 的答案,g(s):g(s):g(s): 劃分一個(gè)州為 sss 是否合法,val(s):val(s):val(s): 劃分州為 sss 的貢獻(xiàn)。
列出狀態(tài)轉(zhuǎn)移方程:f(s)=∑t∈sf(s?t)g(t)(val(t)val(s))pf(s)=\sum_{t\in s}f(s-t)g(t)\Big(\frac{val(t)}{val(s)}\Big)^pf(s)=∑t∈s?f(s?t)g(t)(val(s)val(t)?)p。
顯然能看到有卷積的形式,即 f(s)=∑i?j=?∧i?j=sf(j)g(i)(val(i)val(s))pf(s)=\sum_{i\bigcap j=\empty\wedge i\bigcup j=s}f(j)g(i)\Big(\frac{val(i)}{val(s)}\Big)^pf(s)=∑i?j=?∧i?j=s?f(j)g(i)(val(s)val(i)?)p。
i?j=si\bigcup j=si?j=s 可以直接用 FWT\text{FWT}FWT 做,但是 i?j=?i\bigcap j=\emptyi?j=? 就不好做了。
如果結(jié)合并集為 sss 的信息,也就意味著 ∣i∣+∣j∣=∣s∣|i|+|j|=|s|∣i∣+∣j∣=∣s∣。
對(duì)于 dpdpdp 的設(shè)計(jì)可以再加一維二進(jìn)制狀態(tài)中 111 的個(gè)數(shù)。
f(i,s):sf(i,s):sf(i,s):s 中 111 的個(gè)數(shù)為 iii 的答案,g(i,s):[sg(i,s):[sg(i,s):[s 成立 ]?val(s)]*val(s)]?val(s)。
f(i,s)g(i,s)=∑j=0i?1∑t∈sf(j,s?t)g(i?j,t)f(i,s)g(i,s)=\sum_{j=0}^{i-1}\sum_{t\in s}f(j,s-t)g(i-j,t)f(i,s)g(i,s)=∑j=0i?1?∑t∈s?f(j,s?t)g(i?j,t)。
預(yù)處理貢獻(xiàn)和貢獻(xiàn)的逆元,狀態(tài)是否合法,直接 FWT\text{FWT}FWT 卷積即可。
code
#include <bits/stdc++.h> using namespace std; #define int long long #define mod 998244353 int n, m, p, N; int u[250], v[250], w[25], fa[25], d[25], val[1 << 21], tot[1 << 21], inv[1 << 21]; bool ok[1 << 21]; int f[22][1 << 21], g[22][1 << 21];int qkpow( int x, int y ) {int ans = 1;while( y ) {if( y & 1 ) ans = ans * x % mod;x = x * x % mod;y >>= 1;}return ans; }void fwt( int *c, int f ) {for( int i = 1;i < N;i <<= 1 )for( int j = 0;j < N;j += ( i << 1 ) )for( int k = 0;k < i;k ++ )c[j + k + i] = ( c[j + k + i] + c[j + k] * f % mod + mod ) % mod; }int find( int x ) { return x == fa[x] ? x : fa[x] = find( fa[x] ); }signed main() {scanf( "%lld %lld %lld", &n, &m, &p );for( int i = 1;i <= m;i ++ ) scanf( "%lld %lld", &u[i], &v[i] );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &w[i] );N = 1 << n;for( int s = 0;s < N;s ++ ) {int num = 0;for( int i = 1;i <= n;i ++ ) {if( 1 << i - 1 & s ) num ++, val[s] += w[i];d[i] = 0, fa[i] = i;}tot[s] = num;for( int i = 1;i <= m;i ++ )if( 1 << u[i] - 1 & s and 1 << v[i] - 1 & s ) {int fu = find( u[i] ), fv = find( v[i] );if( fu ^ fv ) num --, fa[fv] = fu;d[u[i]] ++, d[v[i]] ++;}if( num ^ 1 ) ok[s] = 1;num = 0;for( int i = 1;i <= n;i ++ ) num += d[i] & 1;if( num ) ok[s] = 1;if( ok[s] ) g[tot[s]][s] = qkpow( val[s], p );inv[s] = qkpow( qkpow( val[s], p ), mod - 2 );}for( int i = 0;i <= n;i ++ ) fwt( g[i], 1 );f[0][0] = 1;fwt( f[0], 1 );for( int i = 1;i <= n;i ++ ) {for( int j = 0;j < i;j ++ )for( int k = 0;k < N;k ++ )f[i][k] = ( f[i][k] + f[j][k] * g[i - j][k] ) % mod;fwt( f[i], -1 );for( int j = 0;j < N;j ++ ) f[i][j] = tot[j] == i ? f[i][j] * inv[j] % mod : 0;fwt( f[i], 1 ); }printf( "%lld\n", f[n][N - 1] );return 0; }總結(jié)
以上是生活随笔為你收集整理的[WC2018]州区划分(FWT_OR卷积)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: CF662C Binary Table(
- 下一篇: [HNOI2012]集合选数(思维构造