CF1323B Count Subrectangles
\(\Large\textbf{Description: } \large{给定长为 n 的数组 a 和长为 m 的数组 b,数组中的元素均是 0 或 1。有 n\times m的矩阵 c,c_{i,j}=a_i \cdot b_j。请求出矩阵 c 面积为 k 的全 1 子矩阵数量。}\)
\(\Large\textbf{Solution: } \large{观察题目可知,题意就是求a序列的一段长为x连续1区间与b序列的一段长为y连续1区间的个数,且x \times y = k。\\所以可以计算出a序列中连续为1的区间长度,b区间连续为1的区间长度,然后各排一次序。\\在处理a的连续1区间时,去一下重,方便我们后面枚举x。\\枚举a区间中长度为1的区间长度x,然后去b区间二分查找第一个y满足x \times y = k,那么\\当前x对答案的贡献就是 : a序列中区间长度为x的区间个数 \times b序列中长度大于等于\\y的区间个数。}\)
\(\Large\textbf{Code: }\)
#include <cstdio>
#include <algorithm>
#define LL long long
#define gc() getchar()
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
using namespace std;
const int N = 4e5 + 5;
LL n, m, k, cnt, a[N], b[N], s1[N], vis[N], val[N];
LL c[N];
struct S {
int pre, id;
}s[N];
inline int read() {
char ch = gc();
int ans = 0;
while (ch > '9' || ch < '0') ch = gc();
while (ch >= '0' && ch <= '9') ans = (ans << 1) + (ans << 3) + ch - '0', ch = gc();
return ans;
}
inline bool cmp(S x, S y) {
return x.pre < y.pre;
}
inline LL search(LL x) {
int left = 1, right = m, ret = 0;
while (left <= right) {
int mid = (left + right) >> 1;
if (s[mid].pre >= x) ret = mid, right = mid - 1;
else left = mid + 1;
}
return ret ? (m - ret + 1) : 0;
}
int main() {
n = read(), m = read(), k = read();
rep(i, 1, n) {
a[i] = read();
if (a[i]) {
s1[i] = s1[i - 1] + a[i];
if (!vis[s1[i]]) val[++cnt] = s1[i];
++vis[s1[i]];
}
}
rep(i, 1, m) {
b[i] = read();
s[i].id = i; s[i].pre = b[i - 1] && b[i] ? b[i] + s[i - 1].pre : b[i];
}
sort(s + 1, s + 1 + m, cmp);
sort(s1 + 1, s1 + 1 + cnt);
rep(i, 1, cnt) c[i] = c[i - 1] + vis[val[i]];
LL ans = 0; LL tot = c[val[cnt]];
rep(i, 1, cnt) if (val[i] && k % val[i] == 0) ans += (1LL * (tot - c[i - 1])) * search(k / val[i]);
printf("%lld\n", ans);
return 0;
}