原题链接
容易想到 O(3n) O ( 3 n ) 的子集DP
fs=∑t⊆sft∗gs−t f s = ∑ t ⊆ s f t ∗ g s − t
做完了 fs f s 之后还要让 fs=fs∗invs f s = f s ∗ i n v s
发现上面那个方程就是一个子集卷积,只不过会自己卷自己的。
回顾子集卷积怎么搞,类似的,设 f[i][s] f [ i ] [ s ]
我们从小到大枚举这个 i i ,相当于分层进行转移。
同理分层FMT就可以了,复杂度是一样的,于是可以 O(2nn2) O ( 2 n n 2 ) 解决。
#include
#include
#include
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,b,a) for(int i=b;i>=a;--i)
#define efo(i,v,u) for(int i=BB[v],u=B[BB[v]][1];i;i=B[i][0],u=B[i][1])
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define mset(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
char ch;
int read(){int n=0,p=1;for(ch=getchar();ch<'0' || ch>'9';ch=getchar())if(ch=='-') p=-1;for(;'0'<=ch && ch<='9';ch=getchar()) n=n*10+ch-'0';return n*p;}
const int N=23,M=(1<<21)+5,mo=998244353;
ll qmi(ll x,ll n)
{
ll t=1;
for(;n;n>>=1,x=x*x%mo) if(n&1) t=t*x%mo;
return t;
}
bool map[N][N];
int _2[N],n,m,p,in[N],bitcnt[M],fa[N];
int getfa(int x){return fa[x]?fa[x]=getfa(fa[x]):x;}
ll w[N],sum[M],pd[M],f[N][M],g[N][M];
void fmt(ll *a,int sig=1)
{
fo(i,1,n)
fo(s,0,_2[n]-1)
if(s&_2[i-1]) a[s]=(a[s]+(sig>0?(a[s^_2[i-1]]):(mo-a[s^_2[i-1]])))%mo;
}
int main()
{
int x,y;
n=read(),m=read(),p=read();_2[0]=1;fo(i,1,n) _2[i]=_2[i-1]<<1;
fo(i,1,m)
{
x=read(),y=read();
map[x][y]=map[y][x]=1;
}
fo(i,1,n) w[i]=read();
fo(s,1,_2[n]-1)
{
fo(i,1,n) if(s&_2[i-1]) sum[s]=(sum[s]+w[i])%mo,++bitcnt[s];
pd[s]=sum[s]=qmi(sum[s],p);
sum[s]=qmi(sum[s],mo-2);
if(bitcnt[s]==1) {pd[s]=0;continue;}
mset(fa,0);mset(in,0);
bool ok=0;
fo(i,1,n) if(s&_2[i-1])
{
fo(j,1,n) if(s&_2[j-1])
if(map[i][j])
{
++in[i];
int fi=getfa(i),fj=getfa(j);
if(fi!=fj) fa[fj]=fi;
}
if(in[i]&1) {ok=1;break;}
if(!in[i]) {ok=1;break;}
}
int cnt=0;
fo(i,1,n) if(s&_2[i-1])
if(i==getfa(i)) ++cnt;
if(cnt>1) continue;
if(!ok) pd[s]=0;
}
fo(s,1,_2[n]-1) g[bitcnt[s]][s]=pd[s];
fo(i,0,n) fmt(g[i]);
f[0][0]=1;
fo(k,1,n)
{
fmt(f[k-1]);
fo(i,0,k)
fo(s,0,_2[n]-1) f[k][s]=(f[k][s]+f[i][s]*g[k-i][s])%mo;
fmt(f[k],-1);
fo(s,0,_2[n]-1) f[k][s]=f[k][s]*sum[s]%mo;
}
printf("%lld\n",f[n][_2[n]-1]);
return 0;
}