AcWing 3617. 子矩形计数
原题链接
中等
作者:
ITNXD
,
2021-06-03 13:57:36
,
所有人可见
,
阅读 326
详细请查看下方注释内容
参考代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 4e4 + 10;
/*
(x, y)为1当且仅当对应的行和列为1!
全是1的矩形就是行和列有对应从长和宽的连续的1!
面积为k的全1矩形个数就是求行和列连续1的区间的个数(区间满足长度乘积为k)
因此:使用两个数组s1[i],s2[i]保存:行或列连续1长度为i的个数!
关键点:两个数组如何去求!
我们可以枚举以i为右端点的前面连续1有多少种,假设i前面连续1最多有t个,则一共有1 ~ t种连续1,也就是要
将s[1] ~ s[t]全部加上1即可!(表示长度为1 ~ t的连续1的个数多了一种)
对于求解将一段区间加上一个数,这正好是差分的概念,因此我们可以使用差分来解决这个连续区间加数的操作!
注意:n的约数大约是logn级别,边长是n^2级别,n^2logn可能爆int,要使用呢LL!
*/
int a[N], b[N], s1[N], s2[N];
int n, m, k;
void solve(int w[], int s[], int n){
int cnt = 0; // 统计连续1个数
for(int i = 0; i < n; i ++){
if(w[i]){
cnt ++;
// 差分操作求差分数组
s[1] ++, s[cnt + 1] --;
}else cnt = 0;
}
// 将差分数组转化为前缀和数组
for(int i = 1; i <= n; i ++) s[i] += s[i - 1];
}
int main(){
cin >> n >> m >> k;
for(int i = 0; i < n; i ++) cin >> a[i];
for(int i = 0; i < m; i ++) cin >> b[i];
// 求s1,s2数组
solve(a, s1, n), solve(b, s2, m);
LL res = 0;
for(int i = 1; i <= n; i ++)
if(k % i == 0 && k / i <= m) // 两个因子为i 和 k / i
res += s1[i] * s2[k / i];
cout << res << endl;
return 0;
}