AtCoder Regular Contest 115 #D

AtCoder Regular Contest 115 #D

Solution1

考虑用\(\text{FWT}\)来理解这个式子,容易发现\(\text{FWT}\)之后求积的式子,满足

对于任意\((u_i,v_i)\)

如果\(u_i,v_i\)中有一者被选择,答案为0,否则权值\(\times 2\)

那么显然对于一个连通块,设其大小为\(c\),放在一起考虑

\(\text{FWT}\)的式子里它们同时出现或者同时不出现

枚举最后\(\text{FWT}\)回来时的项与在这\(c\)个位置中出现\(i\)

对于选择这个连通块的情况,贡献为\((-1)^i\)

对于不选的情况,贡献为\(1\)

显然只有\(2|i\)时贡献为2,乘上组合数完成转移,连通块之间背包合并

就能得到最终计算答案的项中出现了几个1,然后与\(\text{FWT}\)的系数合并即可

\[\ \]

Solution2

对于一个连通块,考虑取出一个生成树

容易发现,仅使用这个生成树上的边,就能构成任何一个包含\(2k\)个奇点的情况

对于多余的边,类似异或线性基,它们都是可选可不选的

于是直接统计答案即可

Sol1 和 Sol2 的式子是一样的

const int N=5010,P=998244353;
int n,m,dp[N];
ll qpow(ll x,ll k=P-2){
	ll res=1;
	for(;k;k>>=1,x=x*x%P) if(k&1) res=res*x%P;
	return res;
}
vector <int> G[N];
int c,vis[N],C[N][N];
void dfs(int u){
	if(vis[u]) return;
	vis[u]=1,c++;
	for(int v:G[u]) dfs(v);
}

int main(){
	n=rd(),m=rd();
	rep(i,0,n) rep(j,*C[i]=1,i) C[i][j]=C[i-1][j]+C[i-1][j-1],Mod1(C[i][j]);
	rep(i,1,m) {
		int u=rd(),v=rd();
		G[u].pb(v),G[v].pb(u);
	}
	dp[0]=1;
	rep(u,1,n) if(!vis[u]) {
		c=0,dfs(u);
		drep(i,n,0) {
			int s=0;
			rep(j,0,min(i,c)) if(~j&1) {
				s=(s+2ll*dp[i-j]*C[c][j])%P;
			}
			dp[i]=s;
		}
	}
	int d=qpow(2,P-1-n+m);
	rep(i,0,n) printf("%d\n",int(1ll*dp[i]*d%P));
}
posted @ 2021-03-22 18:17  chasedeath  阅读(65)  评论(0编辑  收藏  举报