【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\)
注意到 \(f(E)\) 的值只和 \(E\) 中包含的奇數聯通塊的個數有關,那麼所有的 \(f(E)\) 可以歸為對於 \(k\in[0,n]\) 計算選擇 \(k\) 個不要求不等且都 \(\in[0,R)\) 的數字使得異或和為 \(0\)
考慮對於單個 \(k\),列舉這些數字和 \(R\) 的 \(\rm LCP\) 以及這個位置上有多少個數字選了 \(1\) :
如果這位選擇了 \(1\),後面選數字的方案是字尾位上權值和 \(s\),選擇 \(0\)
暴力求解 \(\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\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!\)
最後統計答案直接將兩個部分得到的權值對位乘起來相加即可
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;
}