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

D.Parity of Tuples

题目大意:

给一个 n ∗ m n*m nm矩阵 ( a ) i j (a)_{ij} (a)ij,行向量为 v i v_i vi, 求 ⊕ x = 0 2 k ( c o u n t ( x ) ∗ 3 x   m o d ( 1 0 9 + 7 ) ) \oplus_{x=0}^{2^k}(count(x) * 3^x\space mod(10^9+7)) x=02k(count(x)3x mod(109+7))
其中 c o u n t ( x ) count(x) count(x)表示 1 2 m ∑ i n ∏ j m ( 1 − ( − 1 ) ∣ a i j   a n d   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 ≤ 1 0 5 1 \leq n \leq 10^5 1n105
1 ≤ m ≤ 10 1 \leq m \leq 10 1m10
1 ≤ k ≤ 20 1 \leq k \leq 20 1k20
0 ≤ a i , j &lt; 2 k 0 \leq a_{i,j} &lt; 2^k 0ai,j<2k

解题过程:

考虑化简以上 c o u n t ( x ) count(x) count(x),由于 ( − 1 ) ∣ a   a n d   x ∣ + ∣ b   a n d   x ∣ = ( − 1 ) ∣ ( a   ⊕   b )   a n d   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 后得到:
1 2 m ∑ i n ∑ S ⊆ v i ( − 1 ) s i z e ( S ) ∗ ( − 1 ) ∣ ( ⊕ j ∈ S a i j )   a n d   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为枚举每个行向量的二进制集合。

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

C k = ∑ i ⊕ j = k A i ∗ B j C_k=\sum_{i\oplus j=k}A_i*B_j Ck=ij=kAiBj
D W T ( A ) i = ∑ j n A j ∗ f i , j DWT(A)_i=\sum_j^nA_j*f_{i,j} DWT(A)i=jnAjfi,j
D W T ( C ) i = D W T ( A ) i ∗ D W T ( B ) i DWT(C)_i=DWT(A)_i*DWT(B)_i DWT(C)i=DWT(A)iDWT(B)i
⇒ f i , j ∗ f i , k = f i , j ⊕ k \Rightarrow f_{i,j}*f_{i,k}=f_{i,j\oplus k} fi,jfi,k=fi,jk
⇒ a n d : f i , j = [ i   a n d   j = = i ] \Rightarrow and : f_{i,j}=[i\space and \space j == i] and:fi,j=[i and j==i]
⇒ o r : f i , j = [ i   a n d   j = = j ] \Rightarrow or : f_{i,j}=[i\space and \space j == j] or:fi,j=[i and j==j]
⇒ x o r : f i , j = ( − 1 ) ∣ i   a n d   j ∣ \Rightarrow xor : f_{i,j}= (-1)^{| i \space and \space j |} xor:fi,j=(1)i and j

注意到 x o r xor xor的形式与上述形式完全一致,所以令
c n t x = ∑ i n ∑ S ∈ i ( − 1 ) s i z e ( S ) cnt_x = \sum_i^n \sum_{S \in i} (-1)^{size(S)} cntx=inSi(1)size(S)
其中 x = ⊕ j ∈ S a i , j x=\oplus_{\atop j \in S} a_{i,j} x=jSai,j,则对于 c n t cnt cnt做沃尔什变换可得:
D W T ( c n t ) x = ∑ j 2 k ∑ i n ∑ S ⊆ v i ( − 1 ) s i z e ( S ) ∗ ( − 1 ) ∣ j   a n d   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
由此可得:
c o u n t ( x ) = 1 2 m ∗ D W T ( c n t ) x count(x)=\frac{1}{2^m} *DWT(cnt)_x count(x)=2m1DWT(cnt)x
预处理 c n t x cnt_x cntx复杂度 O ( n   2 m ) O(n\ 2^m) O(n 2m) F W T FWT FWT复杂度 O ( k   2 k ) O(k\ 2^k) O(k 2k),总复杂度为 O ( n   2 m + k   2 k ) 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;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值