[每日一题] Count Subrectangles

87 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第28天,点击查看活动详情

题目

You are given an array a of length nn and array b of length m both consisting of only integers 0 and 1. Consider a matrix c of size n×m formed by following rule: ci,j=aibjc_i,j=a_i⋅b_j . It's easy to see that c consists of only zeroes and ones too.

How many subrectangles of size (area) k consisting only of ones are there in c?

A subrectangle is an intersection of a consecutive (subsequent) segment of rows and a consecutive (subsequent) segment of columns. I.e. consider four integers x1,x2,y1,y2 (1x1x2n1x1x2n)x1,x2,y1,y2 (1≤x1≤x2≤n1≤x1≤x2≤n) a subrectangle c[x1x2][y1y2]c[x1…x2][y1…y2] is an intersection of the rows x1,x1+1,x1+2,,x2x1,x1+1,x1+2,…,x2 and the columns y1,y1+1,y1+2,,y2 y1,y1+1,y1+2,…,y2.

The size (area) of a subrectangle is the total number of cells in it.

image.png

题意

给定长为 nn 的数组 aa 和长为 mm 的数组 bb,数组中的元素均是 0011。有 n×mn\times m 的矩阵 cci,j=ai×bic,c_{i, j} = a_i \times b_i。请求出矩阵 cc 面积为 kk 的全 11 子矩阵数量。

思路

本题数据范围比较大,考虑直接暴力是不行的。

我们可以选择一个数组,统计其中子段[1n][1 - n] 出现的次数

对于这个子矩阵,是 x×yx \times y的,所以 假设xx是层数 ans[k/x]ans[k / x]即可求出为x层时可以匹配的个数。

然后对于另一个数组,对于每一个1的位置,都去尽可能的匹配它前面最长段的1所构成的面积

例如 [00100111000111][00100111000111], 111111可以匹配到前3个的累加值,1111可以匹配前两个的累加值。

代码

#include <bits/stdc++.h>
const int N = 2e5 + 111;
#define int long long
using namespace std;
int n, m, k;
int g[N], s[N], ans[N], base[N];
signed main() {
    cin >> n >> m >> k;
    for (int i = 1; i <= n; ++ i)
        cin >> g[i];
    for (int i = 1; i <= m; ++ i)
        cin >> s[i];
    int l = 1;
    while (l <= m) {
        while (!s[l] && l <= m) l ++;
        int cnt = 0;
        while (s[l] && l <= m) l ++, cnt ++;
        if (cnt)
            for (int i = 1; i <= cnt; ++ i)
                ans[i] += cnt - i + 1;
    }
    for (int i = 1; i <= n ; ++ i) {
        base[i] += base[i - 1];
        if (k < i) continue;
        if (k % i) continue;
        if (k / i > m) continue;
        base[i] += ans[k / i];
    }
    int pos = 0, st = 1, res = 0;
    while (st <= n) {
        if (!g[st]) pos = st;
        else res += base[st - pos];
        st ++;
    }
    cout << res << endl;
    return 0;
}