【Unknown Source】异或和

Descripition

给定 \(R,n\),求在 \([0,R)\) 中选择 \(n\) 个互不相同的数字满足其异或和为 \(0\) 的方案数 \(\mod 998244353\) 的结果

\(R\) 非常大,给出其二进制下表示中的所有 \(1\) 的位置:共 \(K\) 个从低到高给出的 \(a_i\),其中 \(\max a_i\le 1145141919810\)

\(n,K\le 114514\)

Solution

先求有多少选择数的排列,最后除掉阶乘

考虑一类集合划分容斥,将所有元素分成若干集合,每个集合内部数字相等,对这些集合划分的方式赋以一定的系数使得合法者贡献 \(1\) 次,非法者贡献 \(0\)

这个模型和 \(\rm ABC236 Ex\) 是一样的,将所有元素互不相等的关系转化如下

由于排列中任意两个元素都可能相等,所以可以将元素自身看做一个点,元素之间的相等关系看做边

取出全部边集的一个子集 \(E\),强制每个联通块中的元素数值相等,联通块之间不强制不相等,并要求所有元素的 \(\oplus\) 和为 \(0\) ,贡献系数是 \((-1)^{|E|}\),方案数 \(f(E)\) 是给元素分配数值使其满足相等关系且异或和为 \(0\) 的方案数

关于该容斥系数的正确性

如果图上不存在边(也就是所有元素都相等,是一个合法方案)那么选择边表子集的方案数为 \(1\)

否则有元素相等,不合法,需要证明其所有方案的系数之和为 \(0\),可以找到图上存在的一条边 \(e\),对于所有其它边的选取方案,选择 \(e\) 和不选择 \(e\) 会导致奇偶性不同,系数正负 \(1\) 消去了



注意到 \(f(E)\) 的值只和 \(E\) 中包含的奇数联通块的个数有关,那么所有的 \(f(E)\) 可以归为对于 \(k\in[0,n]\) 计算选择 \(k\) 个不要求不等且都 \(\in[0,R)\) 的数字使得异或和为 \(0\)

考虑对于单个 \(k\),枚举这些数字和 \(R\)\(\rm LCP\) 以及这个位置上有多少个数字选了 \(1\)

如果这位选择了 \(1\),后面选数字的方案是后缀位上权值和 \(s\),选择 \(0\) 的数字中有一个用来最后进行抵消,另外的数字选择方案是当前位的权值 \(b\),方案数即:

\[\sum_{i=0}^{k-1}[2|i]\binom{k}{i} s^{i}b^{k-i-1}=\frac1{2b}((b-s)^k+(b+s)^k-s^k(1+(-1)^k)) \]

暴力求解 \(\Theta(nK)\) 个这样的式子就前功尽弃,由于每位的 \(b,s\) 是固定的,变化的只有 \(k\),尝试计算 \(\sum\limits_{i\ge0} x^{i}\sum\limits_{j=0}^{K-1}\dfrac{s_j^i}{2b_j}=\sum\limits_{j=0}^{K-1}\dfrac{s_j^i}{2b_j(1-x)}\)

使用分治乘法进行通分得到完整多项式,对 \((b\pm s)^k\) 做一样的通分即可

注意 \(k\) 是奇数时 \(\rm LCP\) 只能是 \(0\),直接根据上面的公式来计算即可


要求出来答案,避不开的是对于每个 \(k\in[0,n]\) 求出来有几个 \(f(E)\) 满足有 \(k\) 个联通块大小为奇数

先考察所有选择边将 \(x\) 个点联通的方式 \(\{E\}\) 中,\((-1)^{|E|}\) 之和 \(h(x)\),注意到 \(h(1)=1\)

\(x>1\) 时,用全部方案减去不连通方案,全部方案的权值和上面提及了是 \(0\) ,不连通则枚举 \(1\) 所在联通块的大小

但是在外部点数 \(>1\) 的情况下给它们任意连边的所有方案权值和是 \(0\)

只有一个点时选点有 \(x-1\) 种方案,每个点对应的权值之和都是 \(h(x-1)\) ,所以有 \(h(x)=-(x-1)h(x-1)\) ,得到 \(h(n)=(-1)^{n-1}(n-1)!\)

那么设 \(F(x)\) 为选出一个大小为奇数的集合的 \(\rm EGF\),同时设 \(G(x)\) 为所有偶数大小集合的 \(\rm EGF\) ,使用上面所说的容斥系数可以得到下面的式子

\[\begin{aligned}F(x)&=\sum_{i\ge 0} \dfrac{x^{2i+1}}{2i+1}=\dfrac12(\ln(1+x)-\ln(1-x))\\G(x)&=\exp\left(-R\sum_{i\ge 1}\dfrac{x^{2i}}{2i}\right)=(1-x^2)^{R/2}\end{aligned} \]

直接使用 \(F^{-1}(x)\) 表示 \(F(x)\) 的复合逆,根据复合逆定义有:

\[2F(x)=\ln(\dfrac{1+x}{1-x})\\e^{2F(x)}=\dfrac{1+x}{1-x}\\e^{2x}=\frac{1+F^{-1}(x)}{1-F^{-1}(x)}\\F^{-1}(x)=\frac{e^{2x}-1}{e^{2x}+1} \]

\(H(x)=G(F^{-1}(x))\),有 \(H(F(x))=G(x)\)

套用扩展拉格朗日反演公式:

\[[x^n]H(F(x))=[x^{n-1}]H'(x)\left(\dfrac{x}{F^{-1}(x)}\right)^n \]

\[\begin{aligned}&[x^n]\frac{G}{1-yF}\\ &=[x^{n}]\dfrac{H(F)}{1-yF}\\ &=[x^{n-1}]\dfrac1n\left(\dfrac{H(x)}{1-yx}\right)'\frac{x^n}{F^{-1}(x)^n}\\ &=[x^{n-1}]\dfrac1n\dfrac{H(x)'(1-yx)+yH(x)}{(1-yx)^2}\frac{x^n}{F^{-1}(x)^n}\\ &=[x^{n-1}]\dfrac1n\dfrac{H(x)'+y(H(x)-H'(x)x)}{(1-yx)^2}\frac{x^n}{F^{-1}(x)^n}\\ \end{aligned}\]

由于所需为一个关于 \(y\) 的多项式且每项都有 \(x^n\),那么需要继续进行和式变换

\[\begin{aligned}&[x^{n-1}]\frac{x^n(H(x)'+y(H(x)-xH'(x)))}{nF^{-1}(x)^n}\sum_{i\ge 0}(i+1)(yx)^{i}\\ &=[x^{n-1}]\frac{x^nH(x)'}{nF^{-1}(x)^n}+[x^{n-1}]\left(\frac{x^nH(x)'}{nF^{-1}(x)^n}\sum_{i\ge 1}(i+1)(yx)^{i}+\frac{x^n(H(x)-xH'(x))}{nF^{-1}(x)^n}\sum_{i\ge 1}iy^{i}x^{i-1}\right)\\ \\ &=[x^{n-1}]\frac{x^nH(x)'}{nF^{-1}(x)^n}+\sum_{i\ge 1}y^{i}[x^{n-1}]\left(\frac{x^ix^nH(x)'+ix^{i-1}x^nH(x)}{nF^{-1}(x)^n}\right)\\ \\ \end{aligned}\]

求解负指数次方是很困难的,但是注意到 \(F^{-1}(x)\) 的常数项为 \(0\) 所以可以上下同时除以 \(x^{n}\)

一步一步求复杂度就是 \(\Theta(n\log n)\)

注意到在进行 \(F\) 的乘方运算时每个 \(F\) 之间没有顺序,所以要除掉 \(i!\)


最后统计答案直接将两个部分得到的权值对位乘起来相加即可

卡常注意在分治乘法时不要使用 Poly::Mul 而是展开 NTT

Code

#pragma GCC target("avx")
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
const int N=6e5+10;
int fac[N],ifac[N],inv[N];
int n,K,R;
namespace PART1{
	inline poly get_revF(){
		int pw2=1;
		vector<int> vec1,vec2;
		vec1.resize(n+1); vec2.resize(n+1);
		for(int i=0;i<=n;++i){
			vec1[i]=vec2[i]=mul(ifac[i],pw2);
			ckadd(pw2,pw2);
		}
		ckadd(vec1[0],1); ckdel(vec2[0],1);
		vec1=Inv(vec1,n+1);
		vec2=Mul(vec2,vec1);
		vec2.resize(n+1);
		return vec2;
	}
	vector<int> revF;
	inline poly get_H(){
		vector<int> vec=revF;
		vec=Mul(vec,vec);
		vec.resize(n+1);
		for(auto &t:vec) t=del(0,t);
		ckadd(vec[0],1);
		return qpow(vec,mul(R,inv[2]));
	}
	poly main(){
		revF=get_revF();
		vector<int> H=get_H();
		revF.erase(revF.begin());
		revF=qpow(revF,n);
		revF.resize(n+1);
		revF=Inv(revF,n+1);
		vector<int> dH=deriv(H);
		poly M=Mul(H,revF);
		poly dM=Mul(dH,revF);
		M.resize(n+1); dM.resize(n);
		vector<int> ans={dM[n-1]};
		ans.resize(n+1);
		for(int i=1;i<=n;++i){
			int val1=i==n?0:dM[n-1-i];
			int val2=mul(i,M[n-i]);
			ans[i]=add(val1,val2);
			ckmul(ans[i],ifac[i]);
		}
		for(auto &t:ans) ckmul(t,inv[n]);
		return ans;
	}
}
namespace PART2{
	vector<int> A,T;
	inline pair<vector<int>,vector<int> >solve(int l,int r){
		if(l==r)return {{1},{T[l],del(0,mul(A[l],T[l]))}};
		int mid=(l+r)>>1;
		pair<poly,poly> a=solve(l,mid),b=solve(mid+1,r);
		pair<poly,poly> c;
		int lim=1; while(lim<=a.sec.size()+b.sec.size()) lim<<=1;
		NTT(a.sec,lim,1);
		NTT(b.sec,lim,1);
		NTT(a.fir,lim,1);
		NTT(b.fir,lim,1);
		c.fir.resize(lim);
		c.sec.resize(lim);
		for(int i=0;i<lim;++i){
			c.fir[i]=add(mul(a.fir[i],b.sec[i]),mul(b.fir[i],a.sec[i]));
			c.sec[i]=mul(a.sec[i],b.sec[i]);
		}
		NTT(c.fir,lim,-1); NTT(c.sec,lim,-1);
		while(c.fir.size()>1&&!c.fir.back()) c.fir.pop_back();
		while(c.sec.size()>1&&!c.sec.back()) c.sec.pop_back();
		return c;
	}
	int t[N],s[N];
	poly main(){
		for(int i=1;i<=K;++i) s[i]=add(s[i-1],t[i]=ksm(2,a[i]%(mod-1)));
		A.resize(K); T.resize(K);
		for(int i=1;i<=K;++i){
			A[i-1]=del(t[i],s[i-1]);
			T[i-1]=add(t[i],t[i]);
		}
		pair<poly,poly> tmp=solve(0,K-1);
		tmp.sec.resize(n+1);
		vector<int> vec1=Mul(tmp.fir,Inv(tmp.sec,n+1));;

		for(int i=1;i<=K;++i){
			A[i-1]=add(t[i],s[i-1]);
			T[i-1]=add(t[i],t[i]);
		}
		tmp=solve(0,K-1);
		tmp.sec.resize(n+1);
		vector<int> vec2=Mul(tmp.fir,Inv(tmp.sec,n+1));;

		for(int i=1;i<=K;++i){
			A[i-1]=s[i-1];
			T[i-1]=add(t[i],t[i]);
		}
		tmp=solve(0,K-1);
		tmp.sec.resize(n+1);
		vector<int> vec3=Mul(tmp.fir,Inv(tmp.sec,n+1));;
		vec1.resize(n+1); vec2.resize(n+1); vec3.resize(n+1);
		vector<int> ans=Plus(vec2,vec1);
		for(int i=0;i<=n;++i){
			ckdel(ans[i],vec3[i]);
			if(i&1) ckadd(ans[i],vec3[i]);
			else ckdel(ans[i],vec3[i]); 
		}
		for(int i=1;i<=n;i+=2){
			int S=s[K-1],T=t[K];
			int coef=ksm(add(T,T),mod-2);
			int val=add(ksm(del(T,S),i),ksm(add(T,S),i));
			if(!(i&1)) ckadd(val,mul(2,ksm(S,i))); 
			ans[i]=mul(coef,val);
		}
		ans[0]=1;
		return ans;
	}
}
signed main(){
	freopen("xor.in","r",stdin); freopen("xor.out","w",stdout);
	n=6e5; fac[0]=inv[0]=1;
	for(int i=1;i<=n;++i) fac[i]=mul(fac[i-1],i);
	ifac[n]=ksm(fac[n],mod-2);
	for(int i=n;i>=1;--i) ifac[i-1]=mul(ifac[i],i),inv[i]=mul(ifac[i],fac[i-1]);
	n=read(); K=read();
	for(int i=1;i<=K;++i)a[i]=read<ll>(),ckadd(R,ksm(2,a[i]%(mod-1)));
	vector<int> res1=PART1::main();
	vector<int> res2=PART2::main();
	int ans=0;
	for(int i=0;i<=n;++i) ckadd(ans,mul(res1[i],res2[i]));
	print(ans);
	return 0;
}
posted @ 2022-05-28 20:33  没学完四大礼包不改名  阅读(160)  评论(1)    收藏  举报