UOJ348. 【WC2018】州区划分

UOJ348. 【WC2018】州区划分

http://uoj.ac/problem/348

分析:

  • (g(S)=(sumlimits_{xin S}w_x)^p[合法])
  • (f(S))表示(S)集合内的答案。
  • (f(S)=sumlimits_{Tsubseteq S,|T|>0}g(T)f(S-T)s(S))
  • 这玩意可以使用占位多项式搞搞。
  • 大概就是形如(f(S)=sumlimits_{P|Q=S,|P|+|Q|=S}g(P)h(Q))
  • 多开一维表示(|S|)然后暴力卷这一维即可。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
#define N 2100000
#define mod 998244353
ll f[22][N],g[22][N],A[N],sum[N];
int ea[550],eb[550];
int n,m,p,w[22],CNT[N];
int head[22],to[550],nxt[550],cnt,Q[22],vis[22],du[22];
inline void add(int u,int v) {
	to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
}
ll qp(ll x,ll y) {
	ll re=1; for(;y;y>>=1,x=x*x%mod) if(y&1) re=re*x%mod;
	return re;
}
bool check(int s) {
	int i;
	for(i=1;i<=n;i++) du[i]=head[i]=vis[i]=0; cnt=0;
	for(i=1;i<=m;i++) {
		if((s&(1<<(ea[i]-1))) && (s&(1<<(eb[i]-1))))
			add(ea[i],eb[i]),add(eb[i],ea[i]),du[ea[i]]++,du[eb[i]]++;
	}
	for(i=1;i<=n;i++) if(du[i]&1) return 0;
	int l=0,r=0;
	for(i=1;i<=n;i++) if(s&(1<<(i-1))) {
		Q[r++]=i; vis[i]=1; break;
	}
	while(l<r) {
		int x=Q[l++];
		for(i=head[x];i;i=nxt[i]) if(!vis[to[i]]) {
			vis[to[i]]=1; Q[r++]=to[i];
		}
	}
	return r==CNT[s];
}
void fort(ll *a,int len,int flg) {
	int i,j,k,t;
	for(k=2;k<=len;k<<=1) for(t=k>>1,i=0;i<len;i+=k) for(j=i;j<i+t;j++) {
		if(flg==1) a[j+t]=(a[j+t]+a[j])%mod; else a[j+t]=(a[j+t]-a[j])%mod;
	}
}
int main() {
	scanf("%d%d%d",&n,&m,&p);
	int i,j,k;
	for(i=1;i<=m;i++) scanf("%d%d",&ea[i],&eb[i]);
	for(i=1;i<=n;i++) scanf("%d",&w[i]);
	int mask=(1<<n)-1;
	for(i=1;i<=mask;i++) {
		CNT[i]=CNT[i>>1]+(i&1);
		ll re=0;
		for(j=1;j<=n;j++) if(i&(1<<(j-1))) {
			re+=w[j];
		}
		g[CNT[i]][i]=qp(re,p); sum[i]=qp(g[CNT[i]][i],mod-2);
		if(check(i)) g[CNT[i]][i]=0;
	}
	for(i=1;i<=n;i++) fort(g[i],1<<n,1);
	for(i=0;i<=mask;i++) f[0][i]=1;
	for(i=1;i<=n;i++) {
		for(j=1;j<=i;j++) {
			for(k=0;k<=mask;k++) {
				A[k]=(A[k]+g[j][k]*f[i-j][k]);
			}
		}
		for(k=0;k<=mask;k++) A[k]%=mod;
		fort(A,1<<n,-1);
		for(k=0;k<=mask;k++) {
			f[i][k]=A[k]*sum[k]%mod; A[k]=0;
		}
		if(i<n) fort(f[i],1<<n,1);
	}
	printf("%lld
",(f[n][mask]+mod)%mod);
}
原文地址:https://www.cnblogs.com/suika/p/10165994.html