• 【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;
    }
    
  • 相关阅读:
    简单通讯聊天 群聊功能 Windows下的客户端 Linux下的epoll服务器
    Windows客户端 Linux服务器通讯 字符编码问题
    C++时间标准库时间time和系统时间的使用
    Window7系统安装Ubuntu16双系统
    Window7 系统下重新建立一个新分区
    UltraISO(软碟通) 制作U盘启动盘
    Python 列表反转显示方法
    HTML,CSS,JS个别知识点总结
    Git 创建版本库并实现本地上传数据到GitHub库
    Python爬虫数据保存到MongoDB中
  • 原文地址:https://www.cnblogs.com/yspm/p/16321846.html
Copyright © 2020-2023  润新知