小红的异或之和
思路分析
拿到这道题,我们首先要搞清楚:矩阵 的所有子矩阵之和到底怎么算?
暴力枚举所有子矩阵肯定不行。那我们换个角度想:每个元素 会被多少个子矩阵包含?
一个子矩阵由左上角 和右下角
确定。如果
被包含,需要
且
。
用 1-indexed 来算:
有
种选法(
到
),
有
种选法(
到
)
有
种选法,
有
种选法
所以 的贡献次数为
。
接下来,注意到贡献次数可以行列分离:定义行权重 ,列权重
,那么:
$$
由于 ,异或结果只有两种情况:
:
,对应
的列
:
,对应
的列
因此我们预处理出 和
,然后对每一行
:
- 若
,贡献为
- 若
,贡献为
这样总时间复杂度就从 降到了
。
代码
#include <bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
const long long MOD = 1e9 + 7;
int n;
cin >> n;
vector<int> a(n), b(n);
for(int i = 0; i < n; i++) cin >> a[i];
for(int i = 0; i < n; i++) cin >> b[i];
// col_weight[j] = (j+1) * (n-j) for 0-indexed
long long S_col = 0, S_col_1 = 0;
for(int j = 0; j < n; j++){
long long w = (long long)(j+1) * (n-j) % MOD;
S_col = (S_col + w) % MOD;
if(b[j] == 1){
S_col_1 = (S_col_1 + w) % MOD;
}
}
long long S_col_0 = (S_col - S_col_1 + MOD) % MOD;
long long ans = 0;
for(int i = 0; i < n; i++){
long long rw = (long long)(i+1) * (n-i) % MOD;
if(a[i] == 1){
ans = (ans + rw % MOD * S_col_0 % MOD) % MOD;
} else {
ans = (ans + rw % MOD * S_col_1 % MOD) % MOD;
}
}
cout << ans << endl;
return 0;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
final long MOD = 1000000007L;
int n = sc.nextInt();
int[] a = new int[n], b = new int[n];
for (int i = 0; i < n; i++) a[i] = sc.nextInt();
for (int i = 0; i < n; i++) b[i] = sc.nextInt();
long sCol = 0, sCol1 = 0;
for (int j = 0; j < n; j++) {
long w = (long)(j + 1) * (n - j) % MOD;
sCol = (sCol + w) % MOD;
if (b[j] == 1) sCol1 = (sCol1 + w) % MOD;
}
long sCol0 = (sCol - sCol1 + MOD) % MOD;
long ans = 0;
for (int i = 0; i < n; i++) {
long rw = (long)(i + 1) * (n - i) % MOD;
if (a[i] == 1) {
ans = (ans + rw * sCol0 % MOD) % MOD;
} else {
ans = (ans + rw * sCol1 % MOD) % MOD;
}
}
System.out.println(ans);
}
}
复杂度分析
- 时间复杂度:
,两次遍历数组即可。
- 空间复杂度:
,存储输入数组。

京公网安备 11010502036488号