题目链接:点击查看
题目大意:给出一个数组 a 和数组 b 只由 0 和 1 构成,构造出矩阵 maze[ x ][ y ] = a[ x ] * b[ y ],显然maze矩阵同样只由 0 和 1 构成,现在要求面积为 k 的子矩阵中,有多少个全部为 1
题目分析:再次感觉难度大于 C 题的一道 B 题。。考察的方面很综合,不知道如何分类,就暂且分为思维吧,首先排除n*m*n*m的暴力,接下来一步一步考虑,因为面积为 k 的子矩阵,换一种说法,假设子矩阵的大小为 x * y ,则必须满足 x * y == k 的子矩阵才可能满足条件,所以不难想到要对面积 k 进行因数分解,sqrt( k )的时间复杂度预处理出 k 的所有因数作为子矩阵的长和宽,对于每一对可行的长和宽 ( x , y ) 来说,都需要计算其贡献,接下来说的内容可能有点抽象,后面我会举例子说明的。现在的问题转换为了,给出指定大小的子矩阵 ( x , y ) ,如何计算出其出现次数,通过观察样例给出的矩阵可以发现,假设某个子矩阵的左上角端点为( x1 , y1 ),右下角端点为( x2 , y2 ),若该子矩阵想要全部为 1 的话,那么数组 a[ x1 ] ~ a[ x2 ] 以及 b[ y1 ] ~ b[ y2 ] 的这两段连续区间内必须全部为 1 才行,这样就可以将数组 a 以及数组 b 转换为连续的 1 储存了,比如数组 a 原本为 1011011101 ,那么转换后就变为了 1,2,3,1 了,我们记为 aa 数组和 bb 数组,这样转换后有什么用呢?剩下的其实就可以排列组合计算答案了,还是以大小为( x , y )的子矩阵为例,我们遍历一遍 aa 数组,可以对大小为 x * y 的子矩阵做出贡献,那么必须满足连续的行数大于等于 x 才行,通过平移可以知道,贡献就是 aa[ i ] - x + 1 了,遍历一遍数组aa后,可以计算出有多少种行可以做出贡献,同理遍历一遍 bb 数组后计算出有多少列可以做出贡献,相乘就是总贡献了
下面举一个例子,就拿样例为例,a 数组为 1 0 1,转换为 aa 数组也就变成了 1,1
b 数组为 1 1 1,转换为 bb 数组也就变成了 3
以大小为 ( 1 , 2 ) 的子矩阵为例,我们需要在 aa 数组中找到有多少个连续的行满足 aa[ i ] >= 1,显然有两个
接下来需要在 bb 数组中找到有多少个连续的列,满足 bb[ i ] >= 2 ,因为 bb 数组只有一个元素,且其值为 3 ,那么对列的贡献也就是 2 了,因为可以这样选:(选橙色的列)
1 1 1
也可以这样选:
1 1 1
综上,对于子矩阵 ( 1 , 2 ) 的贡献为 2 * 2 = 4
总时间复杂度为 sqrt( n * m )*( n + m ),我用了unordered_map稍加优化,而且sqrt(n*m)应该也不会拉满,所以评测机给出的反馈是十分不错的
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107#include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<unordered_map> using namespace std; typedef long long LL; typedef unsigned long long ull; const int inf=0x3f3f3f3f; const int N=4e4+100; int a[N],b[N]; vector<pair<int,int>>node; void init(int k) { for(int i=1;i*i<=k;i++) { if(k%i==0) { node.push_back(make_pair(i,k/i)); if(i!=k/i) node.push_back(make_pair(k/i,i)); } } } unordered_map<int,int>A,B; void solve(int a[],int n,unordered_map<int,int>& mp) { int pos=1,cnt=0; while(pos<=n) { while(a[pos]) { pos++; cnt++; } if(cnt) { mp[cnt]++; cnt=0; } pos++; } } int main() { #ifndef ONLINE_JUDGE // freopen("input.txt","r",stdin); // freopen("output.txt","w",stdout); #endif // ios::sync_with_stdio(false); int n,m,k; scanf("%d%d%d",&n,&m,&k); init(k); for(int i=1;i<=n;i++) scanf("%d",a+i); for(int i=1;i<=m;i++) scanf("%d",b+i); solve(a,n,A);//预处理出aa数组和bb数组,存放在unordered_map中 solve(b,m,B); LL ans=0; for(int k=0;k<node.size();k++)//遍历每对因子 { int x=node[k].first,y=node[k].second; LL xx=0,yy=0; for(auto it:A)//行贡献 if(it.first>=x) xx+=it.second*(it.first-x+1); for(auto it:B)//列贡献 if(it.first>=y) yy+=it.second*(it.first-y+1); ans+=xx*yy;//累加贡献 } printf("%lldn",ans); return 0; }
最后
以上就是微笑曲奇最近收集整理的关于CodeForces - 1323B Count Subrectangles(思维)的全部内容,更多相关CodeForces内容请搜索靠谱客的其他文章。
发表评论 取消回复