CF1336E Chiori and Doll Picking 【线性代数,组合计数】

题目描述:给定 (n) 个数 (a_iin[0,2^m)),对所有 (k=0,1,dots,m),求 (sum_{Sin {a_i}}[ ext{popcount}(igoplus_{xin S}x)=k])

数据范围:(nle 2cdot 10^5,mle 53)。部分分 (mle 35)

本文参考官方题解


(A) 是给出的数得到的线性基,( ext{span}(A)) 表示 (A) 张成的线性空间, (F(S)=sum_{xin ext{span}(S)}z^x)(P(S)=sum_{xin ext{span}(S)}z^{ ext{popcount}(x)})

(langle i,j angle= ext{popcount}(i ext{ and } j))。生成函数乘法默认 xor 卷积。

(langle i,k angle+langle j,k angleequiv langle ioplus j,k angle ( ext{mod} 2)),即乘法(and)关于加法(xor)的分配律。


首先大家肯定都会 (O(2^{ ext{rank}(A)})),即枚举线性基的子集。

对于 (mle 35),直接用 meet-in-the-middle,把线性基分成高位和低位两部分,其中低位部分只有在最低 $ lceilfrac{m}{2} ceil$ 位有值。设 (f_{i,S}) 表示对于高位的线性基异或出来的所有值,较高 (lfloorfrac{m}{2} floor) 位的 popcount 为 (i),较低 (lceilfrac{m}{2} ceil)(S) 的方案数。(g_S) 表示低位的线性基异或出 (S) 的方案数。将 (m)(f_i)(g) 做 xor 卷积合并即可。复杂度 (O(m2^{lceilfrac{m}{2} ceil}+m^22^{lfloorfrac{m}{2} floor}))

结果这个做法对满分做法没有一点用处(

满分做法使用了根号分治的思想,对于 ( ext{rank}(A)le lfloorfrac{m}{2} floor) 时使用暴力,对于其他情况考虑寻找一个 (O(2^{m- ext{rank}(A)})) 的做法。


有线性基的一些性质得到:

第一行:线性空间 做 线性空间内的线性变换 得到它自己。
第二行:乘法分配律。
第三、四行:做 FWT。根据这个柿子就可以知道,$	ext{FWT}(F(A))$ 的每一位是 $0$ 或 $2^{	ext{rank}(A)}$。
第五、六行:如果存在一个 $x$ 使得 $2
ot|langle k,x
angle$,则该位不可能为 $2^{	ext{rank}(A)}$,只能为 $0$。

[egin{align*}(z^x) imes F(A)&=F(A) & xin ext{span}(S) \F(A) imes F(A)&=F(A)cdot 2^{ ext{rank}(A)} \ ext{FWT}(F(A))cdot ext{FWT}(F(A))&= ext{FWT}(F(A))cdot 2^{ ext{rank(A)}} \ [z^k] ext{FWT}(F(A))&=sum_{xin ext{span}(A)}(-1)^{langle k,x angle}\&=2^{ ext{rank}(A)}[forall xin ext{span}(A),2|langle k,x angle] \&=2^{ ext{rank}(A)}[forall xin A,2|langle k,x angle]end{align*} ]


定义 (A) 的正交线性基为 (B),使得 (forall xin A,yin B)(2|langle x,y angle)。并且 ( ext{rank}(A)+ ext{rank}(B)=m)

(F(B)cdot 2^{ ext{rank}(A)}= ext{FWT}(F(A)))

至于它怎么求,你可以把线性基中的列进行一些交换,使得它的左边是一个边长 ( ext{rank}(A)) 的单位矩阵。

然后将右边一个矩形对称到它的左下方,右下方是一个边长为 (m- ext{rank}(A)) 的单位矩阵。

(放一个官方题解的图)

很容易检验它就是 (A) 的正交线性基,并且两两之间的 (langle x,y anglein{0,2})


求出正交线性基之后呢,考虑算答案。设 (G_c=sum_{xge 0}z^x[ ext{popcount}(x)=c])

[egin{align*} [z^c]P(A)&=[z^0](A imes G_c) \ &=[z^0] ext{IFWT}( ext{FWT}(F(A))cdot ext{FWT}(G_c)) end{align*} ]

[[z^0] ext{IFWT}(X)=2^{-m}sum_{ige 0}[z^i]X ]

我们知道 ( ext{FWT}(F(A))=F(B)cdot 2^{ ext{rank}(A)})

[[z^c]P(A)=2^{ ext{rank}(A)-m}sum_{dge 0}[z^d]P(B)sum_{ige 0}(-1)^iinom{d}{i}inom{m-d}{c-i} ]

(d) 为枚举 (F(B)) 中每一项的大小,(i) 是 FWT 时的两个集合的交集大小)

直接计算,时间复杂度 (O(2^{lfloorfrac{m}{2} floor}+mn+m^3))

总而言之,正交线性基是一个与原线性基“互补”的东西,同时反映了原线性基的性质。也就找到了 (O(2^{m- ext{rank}(A)})) 的做法。

#include<bits/stdc++.h>
#define Rint register int
using namespace std;
typedef long long LL;
const int N = 63, mod = 998244353;
template<typename T>
inline void read(T &x){
    int ch = getchar(); x = 0;
    for(;ch < '0' || ch > '9';ch = getchar());
    for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
}
template<typename T>
inline bool chmin(T &a, const T &b){if(a > b) return a = b, 1; return 0;}
template<typename T>
inline bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
inline int ksm(int a, int b){
    int res = 1; if(b < 0) b += mod - 1;
    while(b){
        if(b & 1) res = (LL) res * a % mod;
        a = (LL) a * a % mod; b >>= 1;
    }
    return res;
}
inline void qmo(int &x){x += (x >> 31) & mod;}
LL lb[N], a[N], b[N], p[N];
int n, m, k, C[N][N];
inline void insert(LL x){
    for(Rint i = m - 1;~i;-- i) if((x >> i) & 1){
        if(!lb[i]){lb[i] = x; return;}
        x ^= lb[i];
    }
}
inline void dfs(int dep, LL x){
    if(dep == k){++ p[__builtin_popcountll(x)]; return;}
    dfs(dep + 1, x); dfs(dep + 1, x ^ a[dep]);
}
int main(){
    read(n); read(m);
    for(Rint i = 1;i <= n;++ i){
        LL x; read(x); insert(x);
    }
    for(Rint i = 0;i < m;++ i)
        if(lb[i]){
            for(Rint j = i - 1;~j;-- j)
                if((lb[i] >> j) & 1) lb[i] ^= lb[j];
        }
    for(Rint i = 0;i < m;++ i)
        if(lb[i]){
            for(Rint j = 0;j < m;++ j)
                if(!lb[j]) a[k] = (a[k] << 1) | (lb[i] >> j & 1);
            a[k] |= (1ll << m - 1 - k); ++ k;
        }
    if(k <= (m >> 1)){
        dfs(0, 0); int tmp = ksm(2, n - k);
        for(Rint i = 0;i <= m;++ i) printf("%lld ", p[i] * tmp % mod);
    } else {
        for(Rint i = 0;i < m - k;++ i){
            for(Rint j = 0;j < k;++ j)
                if((a[j] >> i) & 1)
                    b[i] |= (1ll << j);
            b[i] |= (1ll << m - 1 - i);
        }
        swap(a, b); k = m - k;
        dfs(0, 0); int tmp = ksm(2, n - m);
        C[0][0] = 1;
        for(Rint i = 1;i <= m;++ i){
            C[i][0] = 1;
            for(Rint j = 1;j <= i;++ j)
                qmo(C[i][j] = C[i - 1][j] + C[i - 1][j - 1] - mod);
        }
        for(Rint c = 0;c <= m;++ c){
            int ans = 0;
            for(Rint d = 0;d <= m;++ d){
                int tt = 0;
                for(Rint i = 0;i <= c;++ i){
                    int ttt = (LL) C[d][i] * C[m - d][c - i] % mod;
                    if(i & 1) qmo(tt -= ttt);
                    else qmo(tt += ttt - mod);
                }
                qmo(ans += (LL) tt * p[d] % mod - mod);
            }
            printf("%lld ", (LL) ans * tmp % mod);
        }
    }
}
原文地址:https://www.cnblogs.com/AThousandMoons/p/12918990.html