CF1323B Count Subrectangles

(Large extbf{Description: } large{给定长为 n 的数组 a 和长为 m 的数组 b,数组中的元素均是 0 或 1。有 n imes m的矩阵 c,c_{i,j}=a_i cdot b_j。请求出矩阵 c 面积为 k 的全 1 子矩阵数量。})

(Large extbf{Solution: } large{观察题目可知,题意就是求a序列的一段长为x连续1区间与b序列的一段长为y连续1区间的个数,且x imes y = k。\所以可以计算出a序列中连续为1的区间长度,b区间连续为1的区间长度,然后各排一次序。\在处理a的连续1区间时,去一下重,方便我们后面枚举x。\枚举a区间中长度为1的区间长度x,然后去b区间二分查找第一个y满足x imes y = k,那么\当前x对答案的贡献就是 : a序列中区间长度为x的区间个数 imes b序列中长度大于等于\y的区间个数。})

(Large extbf{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
", ans);
    return 0;
}
原文地址:https://www.cnblogs.com/Miraclys/p/12545503.html