• CF Round #635 Div.1 Chiori and Doll Picking (hard version)


    CF Round #635 Div.1 Chiori and Doll Picking (hard version)

    考虑对于(a_i)建立线性基(d),并且通过高斯消元重整,使得(d)中 每一个元素的最高位 仅自己包含

    不妨设(k=|d|),一个基底的生成集合为(S(d)),设(A=S(d)),预处理部分复杂度为(O(nm+k^2))

    [ ]

    根据线性基的基本性质,我们知道任何一个(xin S(d))(2^{n-k})种生成方法

    因此我们只需要计算线性基元素异或的答案即可,这样我们将问题规模降低到了(k)

    [ ]

    [ ]

    暴力1

    对于(kleq 27),暴力枚举每个元素是否选择,可以通过预处理让复杂度降至(O(2^k))


    暴力2

    (mleq 35,k>27)

    由于线性基包含(k)个关键01位,(m-k)个非关键01位

    通过高斯消元可以使得基的每一位仅包含一个关键01位

    (dp_{S,i})表示选择了(i)个基,非关键01位异或和为(S)的方案数

    复杂度为(O(2^{m-k}m^2))



    对称暴力

    由于(mleq 53),而我们能够暴力解决(kleq 27),则可以考虑剩下的(m-k)个位,想办法在(O(2^{m-k}))时间内求解

    [ ]

    考虑计算个数为(c)的方案数,我们用一个卷积形式来描述,令(displaystyle F_c(x)=sum_{|T|=c}x^{T})

    则容易发现 (ans_c=[x^{empty}](Aigoplus F_c)),其中(igoplus)表示 异或 (集合对称差) 卷积

    显然我们需要( ext{FWT})来计算这个东西,也就是计算

    ([x^{empty}] ext{FWT}( ext{FWT}(A)cdot ext{FWT}(F_c)))

    先考虑比较复杂的(G= ext{FWT}(A))的计算

    下面你需要良好掌握( ext{FWT})参考


    1: (G(x))中每一非零项系数为(2^k)

    考虑线性基(A)的元素是封闭的,则有(Aigoplus A=Acdot |A|)

    (Gcdot G=Gcdot 2^k),解方程得到([x^S]Gin{0,2^k})


    2:([x^S]G(x)=2^kLongleftrightarrow forall T,|Scap T|equiv 0pmod 2)

    ( ext{FWT})式子

    ([x^S]G(x)=sum (-1)^{|Scap T|} [x^T]A(x))

    (A(x))(2^k)个1构成,故得结论


    确定非零项

    由恒等式(|Xcap S|+|Ycap S|equiv|(Xoplus Y)cap S|pmod 2),得到简化

    1.若(X,Y)对于(S)合法,则(Xoplus Y)同样合法,只需要考虑线性基(d)中元素对于(S)的限制

    2.假设已知(S,T)非零,则(Soplus T)非零,因此可以考虑用一个线性基(d')来描述合法元素


    确定(|d'|)大小

    (2^kS(d')=G)( ext{IFWT}(2^kcdot S(d'))=A)

    带入两边(x^{empty})项的值,容易得到(|S(d')|=2^{m-k}),故(|d'|=m-k)

    (|d'|=m-k)是接近前面猜想的一大跳跃


    构造(d')?

    考虑用0/1矩阵形式描述线性基(d)

    (d)中的元素中的最高位移动到主对角线上最高的(k)个位置,此时每一行一定是一个主对角线元素后面跟上一些位置(ge k+1)的元素

    此时(d')的构造即:主对角线取反,其余位置为转置

    (color{blue} 1) 0 0 (color{blue} 1) 0
    0 (color{blue} 1) 0 0 (color{blue} 1)
    0 0 (color{blue} 1) (color{blue} 1) 0
    (color{red}1) 0 (color{red}1) (color{red}1) 0
    0 (color{red}1) 0 (color{red}1) (color{red}1)

    Proof:

    显然这样构造出的(d')元素最低位独立,因此不线性相关,只需要证明满足限制即可

    首先(d_i)(d'_j)在主对角线上无交,有交部分一定是一个主对角线元素与一个非主对角线元素交

    (d_{i})(d'_j)(d_{i,j},d'_{j,j})有交,则在其关于主对角线对称的位置(d_{i,i},d'_{i,j})处同样有交

    因此交都是成对出现的

    [ ]

    [ ]


    由此我们可以在(2^{m-k})时间内通过暴力枚举得到(G)中每个非零项

    下面考虑( ext{FWT}(F^c))的贡献的部分实际极其简单

    可以根据(G)中每一项(x^S)(|S|)确定( ext{FWT}(F^c))

    ([x^S] ext{FWT}(F^c)=sum_{|T|=c}(-1)^{|Scup T|})

    对于(G)中不同的(|S|)分类,对于(|T|=c),枚举(|Scup T|),添加组合数系数即可计算贡献

    注意最后求出的答案([x^{empty}])为对应项相乘之后求和除去( ext{IFWT})(2^k)

    复杂度为(O(2^{m-k}+m^3+nm))

    const int N=210,P=998244353;
    
    int n,m,c;
    ll d[62],e[63],C[62][62],W[63][63];
    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> Enum(ll *d){
    	static ll a[N],S[1<<15],T[1<<15],bin[1<<15];
    	int n=0,m;
    	rep(i,0,61) if(d[i]) a[n++]=d[i];
    	m=n/2;
    	rep(i,0,m) bin[1<<i]=i;
    	rep(i,1,(1<<m)-1) S[i]=S[i&(i-1)]^a[bin[i&-i]];
    	rep(i,1,(1<<(n-m))-1) T[i]=T[i&(i-1)]^a[bin[i&-i]+m];
    	vector <int> res(::m+1);
    	int X=(1<<m)-1;
    	rep(i,0,(1<<n)-1) res[__builtin_popcountll(S[i&X]^T[i>>m])]++;
    	return res;
    }
    
    int main(){
    	n=rd(),m=rd();
    	rep(i,1,n) {
    		ll x=rd<ll>();
    		drep(i,m-1,0) if(x&(1ll<<i)) {
    			if(!d[i]) {
    				d[i]=x,c++;
    				break;
    			} else x^=d[i];
    		}
    	}
    	if(c<=27) {
    		n=qpow(2,n-c);
    		vector <int> res=Enum(d);
    		rep(i,0,m) res[i]=1ll*res[i]*n%P;
    		rep(i,0,m) printf("%d ",res[i]);
    		return 0;
    	}
    	rep(i,0,m) rep(j,*C[i]=1,i) C[i][j]=(C[i-1][j]+C[i-1][j-1])%P;
    	rep(i,0,m) { // F_i变成j之后的变化
    		rep(j,0,m) rep(k,0,min(i,j)) {
    			W[i][j]=(W[i][j]+1ll*(k&1?-1:1)*C[j][k]*C[m-j][i-k])%P;
    		}
    	}
    	rep(i,0,m-1) if(d[i]) rep(j,i+1,m) if(d[j]&(1ll<<i)) d[j]^=d[i];
    	rep(i,0,m-1) if(d[i]) {
    		rep(j,0,i-1) if(d[i]&(1ll<<j)) e[j]|=1ll<<i;
    	} else e[i]|=1ll<<i;
    	vector <int> t=Enum(e),ans(m+1);
    	n=qpow(2,n-c+c-m+P-1);
    	rep(i,0,m) rep(j,0,m) ans[i]=(ans[i]+1ll*W[i][j]*t[j])%P;
    	rep(i,0,m) ans[i]=1ll*(ans[i]+P)*n%P;
    	rep(i,0,m) printf("%d ",ans[i]);
    }
    
  • 相关阅读:
    【HTML】使用css3和html给网站添加上春节灯笼特效
    【CSS】学习笔记2 字体设置
    【CSS】学习笔记3 段落设置
    【CSS】学习笔记1 使用CSS样式表
    正则
    图片懒加载
    uni-app-组件
    uni-app-condition(条件)启动模式
    uni-app-页面
    uni-app项目目录和开发规范
  • 原文地址:https://www.cnblogs.com/chasedeath/p/14516201.html
Copyright © 2020-2023  润新知