州区划分[WC2018]

题目链接

链接

题意

懒得写了。

题解

判断是否有欧拉回路随便做。

然后设 $g_s=\sum_{i\in s}val_i$,$h_s=[无回路]\times \sum_{i\in s}val_i$

那么状压DP,有 $f_s=\frac{1}{g_s}\sum_{t\subseteq s}f_th_{s-t}$

这个自己卷自己看起来有点难搞啊。

可以发现: $t\subseteq s$ 等价于枚举 $i,j$,使得 $i \ or \ j=s,|i|+|j|=|s|$。

那么就可以对于每个 $|i|$,都搞一个FMT或卷积就好了。

时间复杂度 $O(n^22^n)$。

程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <bits/stdc++.h>
using namespace std;
#define FO(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define fo(i,j,k) for(int i=(j),end_i=(k);i<=end_i;i++)
#define fd(i,j,k) for(int i=(j),end_i=(k);i>=end_i;i--)
#define DEBUG(x) cout<<#x<<"="<<x<<endl;
#define all(x) (x).begin(),(x).end()
#define cle(x) memset(x,0,sizeof(x))
#define ll long long
#define ull unsigned ll
#define db double
#define lb long db
#define pb push_back
#define mp make_pair
#define fi first
#define se second
inline int read()
{
int x=0; char ch=getchar(); bool f=0;
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
return f?-x:x;
}
#define CASET fo(___,1,read())
const ll mod=998244353ll;
inline ll Add(ll x,ll y){x+=y; return (x<mod)?x:x-mod;}
inline ll Dec(ll x,ll y){x-=y; return (x<0)?x+mod:x;}
inline ll Mul(ll x,ll y){return x*y%mod;}
inline ll Pow(ll x,ll y){y%=(mod-1);ll ans=1;for(;y;y>>=1,x=x*x%mod)if(y&1) ans=ans*x%mod;return ans;}
const int N=21;
int x[N*N],y[N*N];
int fa[N],d[N];
ll w[1<<N],iw[1<<N];
int sum[1<<N];
int n,m,p,cnt;
int find(int x)
{
return x!=fa[x]?fa[x]=find(fa[x]):x;
}
inline void merge(int x,int y)
{
x=find(x); y=find(y);
if(x!=y) fa[x]=y;
}
inline bool check(int s)
{
fo(i,0,n-1) if(d[i]&1) return 1;
int rt=-1,x;
fo(i,0,n-1)
if((1<<i)&s)
{
x=find(i);
if(rt==-1) rt=x;
if(rt!=x) return 1;
}
return 0;
}
ll g[N+1][1<<N],f[N+1][1<<N];
inline void FWT(ll *f,int n,int opt)
{
for(int i=1;i<n;i<<=1)
for(int j=0;j<n;j+=(i<<1))
for(int k=0;k<i;k++)
(f[i+j+k]+=opt*f[j+k]+mod)%=mod;
}
void init()
{
int i;
fo(s,1,cnt-1)
fo(i,0,n-1)
if((1<<i)&s)
{
w[s]=w[s^(1<<i)]+w[1<<i];
sum[s]=sum[s^(1<<i)]+1;
break;
}
fo(s,0,cnt-1)
{
fo(i,0,n-1) fa[i]=i,d[i]=0;
fo(i,1,m)
if(((1<<x[i])&s)&&((1<<y[i])&s))
{
d[x[i]]++; d[y[i]]++;
merge(x[i],y[i]);
}
w[s]=Pow(w[s],p); iw[s]=Pow(w[s],mod-2);
f[sum[s]][s]=w[s]*check(s);
}
}

int main()
{
n=read(); m=read(); p=read(); cnt=1<<n;
fo(i,1,m) x[i]=read()-1,y[i]=read()-1;
fo(i,0,n-1) w[1<<i]=read();
init();
g[0][0]=1;
FWT(g[0],cnt,1);
fo(i,1,n)
{
FWT(f[i],cnt,1);
fo(j,0,i-1)
fo(s,0,cnt-1)
g[i][s]=Add(g[i][s],Mul(g[j][s],f[i-j][s]));
FWT(g[i],cnt,-1);
fo(s,0,cnt-1) g[i][s]=(sum[s]==i?Mul(g[i][s],iw[s]):0);
if(i!=n) FWT(g[i],cnt,1);
}
printf("%lld",g[n][cnt-1]);
return 0;
}