Loading

题解:P13275 [NOI2025] 集合

谨以此学习集合容斥、集合幂级数

集合容斥:

原理:

子集形式:

\[\begin{gathered} f(S)=\sum_{T\subseteq S}(-1)^{|S|-|T|} \sum_{P\subseteq T} f(P) \\ \end{gathered} \]

超集形式:

\[\begin{gathered} f(S)=\sum_{T\supseteq S}(-1)^{|T|-|S|} \sum_{P\supseteq T} f(P) \\ \end{gathered} \]

证明:

其实对子集的形式证明即可:

\[\begin{aligned} \mathrm{res} &= \sum_{T\subseteq S}(-1)^{|S|-|T|} \sum_{P\subseteq T} f(P) \\ &= \sum_{P} f(P) \sum_{P\subseteq T\subseteq S} (-1)^{|S|-|T|} \\ &= \sum_{P} f(P) \sum_{T\subseteq (S\setminus P)} (-1)^{|S\setminus P|-|T|} \\ \end{aligned} \]

\(F(S)=\displaystyle\sum_{T\subseteq S}(-1)^{|S|-|T|}\),因此后面的和式可以替换:

\[=\sum_{P} f(P) \times F(S\setminus P) \]

\(F(S)\) 进行研究,考虑枚举 \(|T|=i\)

\[\begin{aligned} F(S) &= \sum_{i=0}^{|S|}\sum_{|T|=i} (-1)^{|S|-i} \\ &= \sum_{i=0}^{|S|}(-1)^{|S|-i} \sum_{|T|=i} 1 \\ &= \sum_{i=0}^{|S|}(-1)^{|S|-i} \binom{|S|}{i} \\ &= \sum_{i=0}^{|S|}(-1)^{|S|-i} \binom{|S|}{i}\times 1^i \\ &= [1+(-1)]^{|S|} \\ &= [S=\emptyset] \end{aligned} \]

因此只有 \(P=S\)\(F(S\setminus P)=1\),此时 \(\mathrm{res}=f(S)\),得证。


[NOI 2025] 集合

简要题意:

定义全集 \(U=[0,2^n)\),\(f(S)=\displaystyle\bigwedge_{i\in S}i,w(S)=\prod_{i\in S}a_i\),求下列式子的值:

\[\sum_{P\subseteq U}\sum_{Q\subseteq U}[f(P)=f(Q)][P\cap Q=\emptyset]w(P\cup Q) \]

解法:

\(P,Q\) 此时都是 \(2^{2^n}\) 级别的,太大不好处理,但是注意到 \(f(S)\) 是一个 \(n\) 位二进制数,\(2^n\) 级别,可以在此处做文章,重新定义 \(U=[0,n)\)

考虑直接枚举 \(f(P)=f(Q)=S\)

\[\sum_{S\subseteq U}\sum_{f(P)=S}\sum_{f(Q)=S,P\cap Q=\emptyset}w(P\cup Q) \]

由于 \(P,Q\) 交集为空,\(w(P\cup Q)=w(P)w(Q)\),变换和式:

\[\sum_{S\subseteq U}\left[\left(\sum_{f(P)=S}w(P)\right)\times\left(\sum_{f(Q)=S,P\cap Q=\emptyset}w(Q)\right)\right] \]

\(F(S)=\displaystyle\sum_{f(P)=S}w(P)\) 容斥,考虑超集容斥:

\[\begin{aligned} F(S) &= \sum_{T\supseteq S} (-1)^{|T|-|S|}\sum_{P\supseteq T} F(P) \\ &= \sum_{T\supseteq S} (-1)^{|T|-|S|}\sum_{f(P)\supseteq T} w(P) \end{aligned} \]

带回原式:

\[\begin{aligned} &= \sum_{S\subseteq U}\left[\left(\sum_{T_1\supseteq S} (-1)^{|T_1|-|S|}\sum_{f(P)\supseteq T_1} w(P)\right)\times\left(\sum_{T_2\supseteq S} (-1)^{|T_2|-|S|}\sum_{f(Q)\supseteq T_2,P\cap Q=\emptyset} w(Q)\right)\right] \\ &= \sum_{T_1}\sum_{T_2}\sum_{S\subseteq (T_1\cap T_2)} (-1)^{|T_1|-|S|+|T_2|-|S|} \left( \sum_{f(P)\supseteq T_1} w(P) \sum_{f(Q)\supseteq T_2,P\cap Q=\emptyset} w(Q) \right) \\ &= \sum_{T_1}\sum_{T_2}\sum_{S\subseteq (T_1\cap T_2)} (-1)^{|T_1|+|T_2|} \times \dots \\ &= \sum_{T_1}\sum_{T_2}2^{|T_1\cap T_2|} (-1)^{|T_1|+|T_2|} \times \left( \sum_{f(P)\supseteq T_1}\sum_{f(Q)\supseteq T_2}[P\cap Q=\emptyset]\prod_{i\in (P\cup Q)}a_i \right) \end{aligned} \]

考虑枚举 \(R=(P\cup Q)\) 来提出 \(\prod\) 的贡献,这样对于 \((P\cup Q)=R\) 所有贡献就是固定的 \(w(R)\),因此我们要对 \((P\cup Q)=R\) 快速计数。

考虑 \(f(P)\supseteq T_1\) 的意义,相当于限定 \(\forall i\in P,i\supseteq T_1\),用 \(C_{T_1}\) 表示 \(T_1\)\(U\) 下的补集,那么 \(P\) 就是 \(C_{T_1}\) 中的数构成的。因此可以构成 \(P,Q\) 的数集就是 \((C_{T_1}\cup C_{T_2})\),因此 \(R\subseteq (C_{T_1}\cup C_{T_2})\),,然后考虑每个数 \(i\in R\) 对方案数的贡献,如果 \(i\in (C_{T_1}\cap C_{T_2})\),那么这个 \(i\) 可以放到 \(P,Q\),贡献为 \(2\),否则只能唯一放入 \(P\)\(Q\),贡献为 \(1\),因此得到:

\[\begin{aligned} &= \sum_{T_1}\sum_{T_2}2^{|T_1\cap T_2|} (-1)^{|T_1|+|T_2|} \times \left( \sum_{R\subseteq (C_{T_1}\cup C_{T_2})} \prod_{i\in R} (1+[i\in C_{T_1}\cap C_{T_2}])\times a_i\right) \end{aligned} \]

拆一下贡献,对于 \(C_{T_1}\cap C_{T_2}\) 部分枚举一个 \(R_1\),另外部分枚举 \(R_2\),得到:

\[\begin{aligned} &= \sum_{T_1}\sum_{T_2}2^{|T_1\cap T_2|} (-1)^{|T_1|+|T_2|} \times \left(\sum_{R_1\subseteq (C_{T_1}\cap C_{T_2})}\prod_{i\in R_1} 2a_i\right)\times \left(\sum_{R_2\subseteq [(C_{T_1}\cup C_{T_2})\setminus (C_{T_1}\cap C_{T_2})]}\prod_{i\in R_2} a_i\right) \end{aligned} \]

还是不够优秀,注意到我们要求这样的值 \(\displaystyle\sum_{T\subseteq S}\prod_{i\in T}a_i\),考虑组合意义,相当于每个位置选有 \(a_i\) 种选择,不选有一种选择,选择方案就有 \((a_i+1)\) 种,于是总方案数,也就对应原来的式子,就是 \(\displaystyle\prod_{i\in S}(a_i+1)\),继续化简:

\[\begin{aligned} &= \sum_{T_1}\sum_{T_2}2^{|T_1\cap T_2|} (-1)^{|T_1|+|T_2|} \times \left(\prod_{i\in (C_{T_1}\cap C_{T_2})}(2a_i+1)\right)\times \left(\prod_{i\in [(C_{T_1}\cup C_{T_2})\setminus (C_{T_1}\cap C_{T_2})]}( a_i+1)\right) \end{aligned} \]

接着化简,\(C_{T_1}\cap C_{T_2}\) 表示不在 \(T_1\) 且不在 \(T_2\),即 \(C_{T_1\cup T_2}\)。类比可以得到 \((C_{T_1}\cup C_{T_2})\setminus (C_{T_1}\cap C_{T_2})=C_{T_1\cap T_2}\setminus C_{T_1\cup T_2}\)。注意到我们其实已经将其转化成了 \(\prod(C_{S})\) 的形式,于是定义 \(f(S)=\displaystyle\prod_{i\in C_{S}}(a_i+1),\quad g(S)=\displaystyle\prod_{i\in C_S} (2a_i+1)\),后半部分被替换成了:\(g(T_1\cup T_2)\displaystyle\frac{f_{T_1\cap T_2}}{f_{T_1\cup T_2}}\),又有并集又有交集,不好处理,考虑全部变成并集,将 \(f_{T_1\cap T_2}\) 变一下,注意到有交集容斥 \(T_1\cap T_2=T_1+T_2-(T_1\cup T_2)\),在补集意义下仍然成立,因此我们得到 \(f_{T_1\cap T_2}=\displaystyle\frac{f_{T_1}f_{T_2}}{f_{T_1\cup T_2}}\)。并且 \(2^{|T_1\cap T_2|}\) 也是交集,同样使用交集容斥,即 \(2^{|T_1|}2^{|T_2|}2^{-|T_1\cup T_2|}\),原式即:

\[\begin{aligned} &= \sum_{T_1}\sum_{T_2}2^{|T_1|}2^{|T_2|}2^{-|T_1\cup T_2|} (-1)^{|T_1|+|T_2|} g(T_1\cup T_2)f_{T_1}f_{T_2}{(f_{T_1\cup T_2})}^{-2} \\ &= \sum_{T_1}\sum_{T_2} [(-2)^{|T_1|}f_{T_1}][(-2)^{|T_2|}f_{T_2}]\frac{g(T_1\cup T_2)}{2^{|T_1\cup T_2|}{(f_{T_1\cup T_2}})^2} \\ \end{aligned} \]

到此已经可以做到 \(O(4^n)\),然后我们考虑令 \(F(S)=(-2)^{|S|}f_{S},\quad G(S)=\displaystyle\frac{g(S)}{2^{|S|}{(f_{S}})^2}\),并提出 \(S=T_1\cup T_2\) 拆掉贡献:

\[\begin{aligned} &= \sum_{T_1}\sum_{T_2} F(T_1)F(T_2)G(T_1\cup T_2) \\ &= \sum_{S}G(S)\sum_{T_1\cup T_2=S} F(T_1)F(T_2) \\ \end{aligned} \]

完美!此时我们发现后面的和式变成了 \(\mathrm{OR-FWT}\) 的标准形式,直接 \(O(2^n n)\) 解决。

但是注意到 \(f_S\) 处在分母上,如果 \(a_i+1=0\),那么除 \(0\) 没有良定义,答案会错,因此这样只能通过 \(B\) 性质。考虑这样一个 \(\texttt{trick}\),将每个数保存成 \(a\cdot 0^b\) 的形式,如果 \(b=0\) 值就是 \(a\),否则是 \(0\),这样乘除就有良定义了,不过在加减法的运算中就比较奇怪,如果 \(a_1\ne a_2\) 那么两个数相当于被扩域成多项式,不过由于最终只有最低此项(即 \(b=0\))的位置有用,所以直接保留 \(b\) 小的数作为结果即可。

$O(2^nn)$ B性质
void FWT(int f[],int op)
{
	for (int mid=1;mid<(1<<n);mid<<=1)
	{
		for (int i=0;i<(1<<n);i+=(mid<<1))
		{
			for (int j=0;j<mid;j++)
			{
				adm(f[i+j+mid],Mod(f[i+j]*op));
			}
		}
	}
}

void solve()
{
	cin >> n; 
	for (int i=0;i<(1<<n);i++) 
	{
		cin >> a[i];
		f[i]=Mod(a[i]+1); g[i]=Mod(2ll*a[i]%mod+1);
	}
	for (int k=0;k<n;k++)
	{
		for (int i=0;i<(1<<n);i++)
		{
			if (!((i>>k)&1))
			{
				f[i]=(ll)f[i]*f[i^(1<<k)]%mod;
				g[i]=(ll)g[i]*g[i^(1<<k)]%mod;
			}
		}
	}
	for (int i=0;i<(1<<n);i++)
	{
		F[i]=(1ll<<ppc[i])*(ppc[i]&1 ? mod-1 : 1)%mod*f[i]%mod;
		int iv=qmi(f[i],mod-2);
		G[i]=(ll)g[i]*iv2[ppc[i]]%mod*iv%mod*iv%mod;
	}
	
	FWT(F,1);
	for (int i=0;i<(1<<n);i++) F[i]=(ll)F[i]*F[i]%mod;
	FWT(F,-1);
	
	int ans=0;
	for (int i=0;i<(1<<n);i++) adm(ans,(ll)G[i]*F[i]%mod);
	cout << ans << "\n";
}
$O(2^nn)$ 正解
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long ll;
const int mod=998244353;
inline int Mod(int x) { return x<0 ? x+mod : (x>=mod ? x-mod : x); }
inline void adm(int &x,int y) { x=Mod(x+y); }
inline int qmi(ll a,int b) 
{
	ll res=1;
	for (;b>>=1;a=a*a%mod) if (b&1) res=res*a%mod;
	return res;
}

struct poly
{
	int x,k;
	poly() { x=0,k=0; }
	poly(int _x) 
	{
		if (_x) { x=_x,k=0; }
		else { x=1,k=1; }
	}
	poly(int _x,int _k): x(_x),k(_k) {}
	friend poly operator + (const poly &lhs,const poly &rhs)
	{
		if (lhs.k==rhs.k) return poly(Mod(lhs.x+rhs.x),lhs.k);
		else return lhs.k<rhs.k ? lhs : rhs;
	}
	friend poly operator - (const poly &lhs,const poly &rhs) 
	{
		if (lhs.k==rhs.k) return poly(Mod(lhs.x-rhs.x),lhs.k);
		else return lhs.k<rhs.k ? lhs : poly(Mod(-rhs.x),rhs.k);
	}
	friend poly operator * (const poly &lhs,const poly &rhs) { return poly((ll)lhs.x*rhs.x%mod,Mod(lhs.k+rhs.k)); }
	friend poly inv(const poly &o) { return poly(qmi(o.x,mod-2),Mod(-o.k)); }
	friend poly operator / (const poly &lhs,const poly &rhs) { return lhs*inv(rhs); }
};

const int N=(1<<20)|1;
int n;
int a[N];
poly f[N],g[N];
int iv2[N],ppc[N];
poly F[N],G[N];

void FWT(poly f[],int op)
{
	for (int mid=1;mid<(1<<n);mid<<=1)
	{
		for (int i=0;i<(1<<n);i+=(mid<<1))
		{
			for (int j=0;j<mid;j++)
			{
				poly &v=f[i+j+mid];
				if (op==1) v=v+f[i+j];
				else v=v-f[i+j];
			}
		}
	}
}

void solve()
{
	cin >> n; 
	for (int i=0;i<(1<<n);i++) 
	{
		cin >> a[i];
		f[i]=poly(Mod(a[i]+1)); g[i]=poly(Mod(2ll*a[i]%mod+1));
	}
	for (int k=0;k<n;k++)
	{
		for (int i=0;i<(1<<n);i++)
		{
			if (!((i>>k)&1))
			{
				f[i]=f[i]*f[i^(1<<k)];
				g[i]=g[i]*g[i^(1<<k)];
			}
		}
	}
	for (int i=0;i<(1<<n);i++)
	{
		F[i]=poly((1ll<<ppc[i])*(ppc[i]&1 ? mod-1 : 1)%mod)*f[i];
		poly iv=inv(f[i]);
		G[i]=g[i]*poly(iv2[ppc[i]])*iv*iv;
	}
	
	FWT(F,1);
	for (int i=0;i<(1<<n);i++) F[i]=F[i]*F[i];
	FWT(F,-1);
	
	int ans=0;
	for (int i=0;i<(1<<n);i++) 
	{
		poly res=F[i]*G[i];
		if (!res.k) adm(ans,res.x);
	}
	cout << ans << "\n";
}

int main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	
	int inv2=(mod+1)/2;
	iv2[0]=1;
	for (int i=1;i<N;i++) iv2[i]=(ll)iv2[i-1]*inv2%mod;
	for (int i=1;i<N;i++) ppc[i]=ppc[i>>1]+(i&1);
	
	int cid,T; cin >> cid >> T;
	while (T--) solve();
	
	return 0;
}
posted @ 2025-09-03 20:08  STDJCY  阅读(47)  评论(0)    收藏  举报