Solution
首先对于每个子集判断是否可以单独成一个州,也就是判断是否存在欧拉回路,存在欧拉回路当且仅当图连通且每个点的度数都为偶数。设
s
u
m
S
sum_S
sumS为集合
S
S
S所有元素
w
w
w之和,若
S
S
S能成一个州,
g
S
=
s
u
m
S
p
g_S={sum_S}^p
gS=sumSp,设
f
S
f_S
fS为集合
S
S
S所有划分方案的乘积之和,那么
f
S
=
1
s
u
m
S
p
∑
f
T
g
S
−
T
,
T
&
(
S
−
T
)
=
0
f_S={1\over {sum_S}^p}\sum f_{T}g_{S-T},T\&(S-T)=0
fS=sumSp1∑fTgS−T,T&(S−T)=0。这就是个子集卷积,不过会自己卷自己,要按照
1
1
1的个数分层转移。
不知道为什么,用异或卷积比用或卷积做慢了
10
s
10s
10s……
Code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int inf=2147483647;
const int mod=998244353,inv=(mod+1)/2;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
inline void upd(int&x,int y){x+=y;if(x>=mod)x-=mod;}
int Pow(int x,int y)
{
if(!y)return 1;
int t=Pow(x,y>>1),re=(LL)t*t%mod;
if(y&1)re=(LL)re*x%mod;
return re;
}
int n,m,p,w[22],f[22][1<<21],g[22][1<<21],s[1<<21],o[1<<21],invs[1<<21],deg[22];
vector<int>h[22];
int tS;
void dfs(int x,int S)
{
tS|=(1<<(x-1));
for(int i=0;i<h[x].size();i++)
{
int y=h[x][i];
if(S&(1<<(y-1))&&!(tS&(1<<(y-1))))dfs(y,S);
}
}
LL sb=0;
void fwt(int *a,int o)
{
for(int i=0;i<n;i++)
for(int j=(1<<n)-1;j>=0;j--)
if(j&(1<<i))
{
if(o==1)a[j]=(a[j]+a[j^(1<<i)])%mod;
else a[j]=(a[j]-a[j^(1<<i)]+mod)%mod;
}
}
int main()
{
n=read(),m=read(),p=read();int N=1<<n;
o[0]=0;for(int i=1;i<(1<<n);i++)o[i]=o[i>>1]+(i&1);
for(int i=1;i<=m;i++)
{
int x=read(),y=read();
h[x].push_back(y),h[y].push_back(x);
}
for(int i=1;i<=n;i++)w[i]=read();
for(int S=1;S<(1<<n);S++)
{
s[S]=0;int pp;bool flag=true;
for(int i=1;i<=n;i++)deg[i]=0;
for(int i=1;i<=n;i++)
if((1<<(i-1))&S)
{
s[S]+=w[i],pp=i;
for(int j=0;j<h[i].size();j++)
{
int y=h[i][j];if(y<i)continue;
if((1<<(y-1))&S)deg[y]++,deg[i]++;
}
}
for(int i=1;i<=n;i++)
if((1<<(i-1))&S&°[i]&1)flag=false;
tS=0;dfs(pp,S);invs[S]=Pow(Pow(s[S],mod-2),p);
if(tS==S&&flag)g[o[S]][S]=0;else g[o[S]][S]=Pow(s[S],p);
}
for(int i=1;i<=n;i++)fwt(g[i],1);
f[0][0]=1;fwt(f[0],1);
for(int S=1;S<(1<<n);S<<=1)f[1][S]=(g[1][S]?1:0);fwt(f[1],1);
for(int i=2;i<=n;i++)
{
for(int j=1;j<=i;j++)
for(int S=0;S<N;S++)
upd(f[i][S],(LL)f[i-j][S]*g[j][S]%mod);
fwt(f[i],-1);
for(int S=0;S<N;S++)
if(o[S]!=i)f[i][S]=0;
else f[i][S]=(LL)f[i][S]*invs[S]%mod;
fwt(f[i],1);
}
fwt(f[n],-1);
printf("%d",f[n][(1<<n)-1]);
}