zoukankan      html  css  js  c++  java
  • HDU

    传送门


    【分析】

    考虑 ((ivee j)=(iwedge j)vee (ioplus j))

    (x=ivee j,y=ioplus jRightarrow x=yvee kRightarrow k=xoplus y(k,ysubseteq x))

    (quad C_k)

    (displaystyle =sum_{iwedge j=k}A_{ioplus j}B_{ivee j})

    (displaystyle =sum_{xoplus y=k}[ysubseteq x]A_yB_xsum_isum_j[ivee j=x][i wedge j=k])

    (displaystyle =sum_{xoplus y=k}[ywedge x=y]A_yB_x2^{pc(x)-pc(k)})

    其中 (pc(n)) 代表 (n) 二进制中 (1) 的个数

    考虑到 (k,y) 均为 (x) 的子集,且 (k=xoplus y)

    (pc(x)-pc(k)=pc(y)) ,代入原式得到

    (displaystyle C_k=sum_{xoplus y=k\ ywedge x=y}(A_ycdot 2^{pc(y)})cdot B_x)

    考虑到式子的本质,像是对于 (k) ,枚举另一个与它不交的集合 (y) ,把两者的并集和 (y) 集合的贡献统计到 (k)


    类似的东西是普通的子集卷积: (displaystyle C_n=sum_{ivee j=n\ iwedge j=0}A_iB_j)

    这个代表的含义是:将集合 (n) 划分成两部分,将两个部分的贡献统计到 (C_n)

    实现的方法在于:拓广一维,使得统计 (i)(n) 的贡献时,强制使得统计的另一个贡献来源于 ((n-i))

    由于子集卷积是对一个集合的划分,故可以得出:(pc(n)=pc(i)+pc(n-i))

    因此,考虑 (i) 的贡献时,强制其从 (pc(i)) 的维度转移过来,则可强制另一位从 (pc(n-i)) 转移;即可保证 (i)(j) 不交

    实现代码则如下:

    inline int pc(int n) { return __builtin_popcount(n>>10)+__builtin_popcount(n&1023); }
    inline void FST(int *a,int *b,int *c,int bits, int len){
        for(int i=0;i<len;++i) A[pc(i)][i]=a[i];
        for(int i=0;i<len;++i) B[pc(i)][i]=b[i];
        for(int i=0;i<=bits;++i) FWT(A[i], len, 0), FWT(B[i], len, 0);
        for(int x=0;x<=bits;++x)
            for(int y=0;y<=x;++y)
                for(int i=0;i<len;++i)
                    C[x][i]=add( C[x][i] , (ll)A[y][i]*B[x-y][i]%P );
        for(int i=0;i<=bits;++i) FWT(C[i], len, 1);
        for(int i=0;i<len;++i) c[i]=C[pc(i)][i];
    }
    

    总复杂度 (O(nlog^2 n), n=2^bits=len)


    这题类似的处理

    据说叫子集异或卷积,前面的叫子集或卷积

    即考虑 (A_y) 的贡献从 (y) 转移时,强制从 (pc(y)) 转移,另一位 (B_x) 即可强制从 (pc(k+y)) 转移

    inline int pc(int n) { return __builtin_popcount(n>>10)+__builtin_popcount(n&1023); }
    inline void FST(int *a,int *b,int *c,int bits, int len){
        for(int i=0;i<len;++i) A[pc(i)][i]=a[i];
        for(int i=0;i<len;++i) B[pc(i)][i]=b[i];
        for(int i=0;i<=bits;++i) FWT(A[i], len, 0), FWT(B[i], len, 0);
        for(int x=0;x<=bits;++x)
            for(int y=0;y<=x;++y)
                for(int i=0;i<len;++i)
                    C[x-y][i]=add( C[x-y][i] , (ll)A[y][i]*B[x][i]%P );
        for(int i=0;i<=bits;++i) FWT(C[i], len, 1);
        for(int i=0;i<len;++i) c[i]=C[pc(i)][i];
    }
    

    复杂度相同


    【代码】

    最后上总代码,无封装

    #include<bits/stdc++.h> 
    using namespace std;
    typedef long long ll;
    const int MOD=998244353, M=1<<20;
    int m, A[20][M], B[20][M], C[20][M];
    inline int pc(int n) { return __builtin_popcount(n>>10)+__builtin_popcount(n&1023); }
    inline int add(int a,int b) { return (a+b>=MOD)?(a+b-MOD):(a+b); }
    inline int dis(int a,int b) { return (a-b<0)?(a-b+MOD):(a-b); }
    inline int shr(int n,int p) { return p?((n&1)?(n+MOD>>1):(n>>1)):n; }
    
    inline void FWT(int *a,int len,int op){
    	for(int k=0;1<<k<len;++k) for(int i=0;i<len;++i) if(~i>>k&1){
    		int j=i^(1<<k), x, y;
    		x=add(a[i], a[j]), y=dis(a[i], a[j]);
    		a[i]=shr(x,op), a[j]=shr(y,op);
    	}
    }
    int main(){
    	ios::sync_with_stdio(0);
    	cin.tie(0); cout.tie(0);
    	cin>>m;
    	for(int i=0,n;!(i>>m);++i) cin>>A[pc(i)][i], A[pc(i)][i]=A[pc(i)][i]*(1ll<<pc(i))%MOD;
    	for(int i=0,n;!(i>>m);++i) cin>>B[pc(i)][i];
    	for(int i=0;i<=m;++i) FWT(A[i],1<<m,0), FWT(B[i],1<<m,0);
    	for(int x=0;x<=m;++x)
    		for(int y=0;y<=x;++y)
    			for(int i=0;!(i>>m);++i)
    				C[x-y][i]=add(C[x-y][i], (ll)A[y][i]*B[x][i]%MOD);
    	for(int i=0;i<=m;++i) FWT(C[i],1<<m,1);
    	int ans=0;
    	for(int i=(1<<m)-1;~i;--i) ans=add(ans*1526ll%MOD, C[pc(i)][i]);
    	cout<<ans<<"
    ";
    	cout.flush();
    	return 0;
    }
    
  • 相关阅读:
    HDOJ 1207 汉诺塔II
    [转]写代码的小女孩
    POJ Subway tree systems
    HDOJ 3555 Bomb (数位DP)
    POJ 1636 Prison rearrangement (DP)
    POJ 1015 Jury Compromise (DP)
    UVA 10003
    UVA 103 Stacking Boxes
    HDOJ 3530 Subsequence
    第三百六十二、三天 how can I 坚持
  • 原文地址:https://www.cnblogs.com/JustinRochester/p/14599371.html
Copyright © 2011-2022 走看看