考虑按位计算贡献
对于 AND 运算,只有全 \(1\) 子矩阵才会有贡献
对于 OR 运算,所以非全 \(0\) 子矩阵均有贡献
如果求一个 01 矩阵中全 \(0/1\) 子矩阵的个数呢?
单调栈可以 \(O(n^2)\) 实现
总时间复杂度 \(O(n^2k)\) 其中 \(k\) 是二进制位数
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e3 + 6, P = 1e9 + 7;
int n, a[N][N], h[N], s[N], w[N], p;
ll ans[2];
inline ll get(int x) {
return (1ll * x * (x + 1)) >> 1;
}
inline ll calc(int o) {
ll cnt = 0;
for (int j = 1; j <= n; j++) h[j] = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if ((a[i][j] & 1) == o) ++h[j];
else h[j] = 0;
if (h[j] > s[p]) s[++p] = h[j], w[p] = 1;
else {
int k = 0;
while (s[p] > h[j]) {
k += w[p];
cnt += (s[p] - max(s[p-1], h[j])) * get(k);
--p;
}
s[++p] = h[j], w[p] = k + 1;
}
}
int k = 0;
while (p) {
k += w[p];
cnt += (s[p] - s[p-1]) * (get(k));
--p;
}
}
return cnt % P;
}
void work(int o) {
if (o == 32) return;
ans[0] += calc(1) * (1 << o) % P, ans[0] %= P;
ans[1] += (get(n) * get(n) % P - calc(0)) * (1 << o) % P, ans[1] %= P;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
a[i][j] >>= 1;
work(o + 1);
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
scanf("%d", &a[i][j]);
work(0);
cout << (ans[0] + P) % P << " " << (ans[1] + P) % P << endl;
return 0;
}