2019牛客暑期多校训练营(第一场) D.Parity of Tuples (FWT)

本文介绍了一种利用沃尔什变换解决矩阵相关问题的方法。通过化简count(x)表达式,并结合离散沃尔什变换原理,文章详细阐述了如何计算特定矩阵的异或和。最终提出了一种高效算法,其复杂度为O(n2^m + k2^k)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

D.Parity of Tuples

题目大意:

给一个n∗mn*mnm矩阵(a)ij(a)_{ij}(a)ij,行向量为viv_ivi, 求⊕x=02k(count(x)∗3x mod(109+7))\oplus_{x=0}^{2^k}(count(x) * 3^x\space mod(10^9+7))x=02k(count(x)3x mod(109+7))
其中count(x)count(x)count(x)表示12m∑in∏jm(1−(−1)∣aij and x∣)\frac{1}{2^m} \sum_i^n \prod_j^m (1-(-1)^{|a_{ij} \space and \space x| })2m1injm(1(1)aij and x), ⊕\oplus表示异或,∣a∣|a|a表示a的二进制中1的个数。

数据范围:

1≤n≤1051 \leq n \leq 10^51n105
1≤m≤101 \leq m \leq 101m10
1≤k≤201 \leq k \leq 201k20
0≤ai,j&lt;2k0 \leq a_{i,j} &lt; 2^k0ai,j<2k

解题过程:

考虑化简以上count(x)count(x)count(x),由于(−1)∣a and x∣+∣b and x∣=(−1)∣(a ⊕ b) and x∣(-1)^{|a\space and \space x| + |b\space and\space x|}= (-1)^{|(a \space \oplus \space b) \space and \space x|}(1)a and x+b and x=(1)(a  b) and x
则展开∏\prod后得到:
12m∑in∑S⊆vi(−1)size(S)∗(−1)∣(⊕j∈Saij) and x∣ \frac{1}{2^m} \sum_i^n \sum_{S \subseteq {v_i}} (-1)^{size(S)} * (-1)^{|(\oplus_{\atop j \in S}a_{ij}) \space and \space x |} 2m1inSvi(1)size(S)(1)(jSaij) and x
其中s为枚举每个行向量的二进制集合。

这里可以观察到和离散沃尔什变换相似的地方,即:

Ck=∑i⊕j=kAi∗BjC_k=\sum_{i\oplus j=k}A_i*B_jCk=ij=kAiBj
DWT(A)i=∑jnAj∗fi,jDWT(A)_i=\sum_j^nA_j*f_{i,j}DWT(A)i=jnAjfi,j
DWT(C)i=DWT(A)i∗DWT(B)iDWT(C)_i=DWT(A)_i*DWT(B)_iDWT(C)i=DWT(A)iDWT(B)i
⇒fi,j∗fi,k=fi,j⊕k\Rightarrow f_{i,j}*f_{i,k}=f_{i,j\oplus k}fi,jfi,k=fi,jk
⇒and:fi,j=[i and j==i]\Rightarrow and : f_{i,j}=[i\space and \space j == i]and:fi,j=[i and j==i]
⇒or:fi,j=[i and j==j]\Rightarrow or : f_{i,j}=[i\space and \space j == j]or:fi,j=[i and j==j]
⇒xor:fi,j=(−1)∣i and j∣\Rightarrow xor : f_{i,j}= (-1)^{| i \space and \space j |}xor:fi,j=(1)i and j

注意到xorxorxor的形式与上述形式完全一致,所以令
cntx=∑in∑S∈i(−1)size(S)cnt_x = \sum_i^n \sum_{S \in i} (-1)^{size(S)}cntx=inSi(1)size(S)
其中x=⊕j∈Sai,jx=\oplus_{\atop j \in S} a_{i,j}x=jSai,j,则对于cntcntcnt做沃尔什变换可得:
DWT(cnt)x=∑j2k∑in∑S⊆vi(−1)size(S)∗(−1)∣j and x∣ DWT(cnt)_x=\sum_j^{2^k}\sum_i^n\sum_{S \subseteq v_i} (-1)^{size(S)}*(-1)^{|j \ and \ x|} DWT(cnt)x=j2kinSvi(1)size(S)(1)j and x
由此可得:
count(x)=12m∗DWT(cnt)xcount(x)=\frac{1}{2^m} *DWT(cnt)_xcount(x)=2m1DWT(cnt)x
预处理cntxcnt_xcntx复杂度O(n 2m)O(n\ 2^m)O(n 2m)FWTFWTFWT复杂度O(k 2k)O(k\ 2^k)O(k 2k),总复杂度为O(n 2m+k 2k)O(n \ 2^m + k \ 2^k)O(n 2m+k 2k)

// Cease to struggle and you cease to live
// D.cpp
// Created by Nickwzk
#include <bits/stdc++.h>
using namespace std;

inline int read() {
	int x = 0, ch = getchar(); bool fg = 1;
	while(ch < '0' || ch > '9') { if(ch == '-') fg = 0; ch = getchar(); } 
	while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return fg ? x : -x;
}
const int mod = 1e9 + 7;
void FWT(vector<int> &a,int n) {
    for(int i = 2;i <= n; i <<= 1) {
        for(int j = 0; j < n; j += i) {
            for(int d = 0, w = i >> 1; d < w; d++){
                int u = a[j + d], v = a[j + d + w];
                a[j + d] = u + v, a[j + d + w] = u - v;
            }
        }
    }
}
void dfs(vector<int> &cnt, const vector<int> &a, int i, int x, int p) {
	if(i < a.size()) {
		dfs(cnt, a, i + 1, x, p);
		dfs(cnt, a, i + 1, x ^ a[i], -p);
	}
	else {
		cnt[x] += p;
	}
}
int main() {
	int n, m, k;
	while(~scanf("%d%d%d", &n, &m, &k)) {
		auto cnt = vector<int>(1 << k, 0);
		auto a = vector<int>(m);
		for(int i = 0; i < n; i++) {
			for(int j = 0; j < m; j++) a[j] = read();
			dfs(cnt, a, 0, 0, 1);
		}
		FWT(cnt, 1 << k);
		int ans = 0, pw = 1 << m, w = 1;
		for(int x = 0; x < (1 << k); x++) {
			ans ^= (long long)w * (cnt[x] / pw) % mod;
			w = (long long)w * 3 % mod;
		}
		printf("%d\n", ans);
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值