CF-div2-626-B. Count Subrectangles

先想到,
假如行有n个连续为1,列上有m个连续为1,则可以组成nm大小的矩阵。
比如行1个连续,列2个连续。可以构成c[1][1]=1,c[1][2]=1,size=1
2=2;

然后就好办了。

先想到一个暴力的思路,然后逐步优化。
1.枚举x
2.枚举y,当x*y == k,就是为了去构成大小为k的矩阵嘛。
3.O(n^2)找出a数组长度为x且全1的个数,找出b数组长度为y且全1的个数,二者相乘(乘法原理,种类个数),累加即可。

考虑优化的方案。
首先枚举y,可以变成计算y,y = k/x(当k%x==0)
然后找出a数组长度为x且全1的个数,可以使用前缀和优化成O(n)

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 4e5+10;
int n,m,k;
ll a[maxn],b[maxn],col[maxn],row[maxn];
unordered_map<int,int> mp;
int main(){
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++) {
		cin>>a[i];
		row[i] = row[i-1] + a[i];
	}
	for(int i=1;i<=m;i++) {
		cin>>b[i];
		col[i] = col[i-1] + b[i];
	}
	ll ans = 0;
	for(int i=1;i<=n;i++){
		if(k%i==0) mp[i] = k/i;
	}
	for(auto it:mp){
		int x = it.first;
		int y = it.second;
			ll cnt1 = 0,cnt2 = 0; //表示能构成行(列)为x(y)的个数 
			for(int i=1;i<=n-x+1;i++){
				if(row[i+x-1] - row[i-1] == x) //如果这段连续长度为x且这一段全为1 
					cnt1 += 1;
			}
			for(int i=1;i<=m-y+1;i++){
				if(col[i+y-1] - col[i-1] == y) //如果这段连续长度为y且这一段全为1 
					cnt2 += 1;
			}
			ans += cnt1*cnt2; //乘法原理 能组成cnt1*cnt2种方案构成size为k的矩形 
	}
	cout<<ans;
	return 0;
} 
/*
3 3 2
1 0 1
1 1 1
*/
原文地址:https://www.cnblogs.com/fisherss/p/12450493.html