专栏文章
题解:P14209 [ROI 2016 Day2] 视频监控管理
P14209题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @minlba4r
- 此快照首次捕获于
- 2025/12/02 04:16 3 个月前
- 此快照最后确认于
- 2025/12/02 04:16 3 个月前
首先观察到题目中的四个按钮操作其实就是将每行或每列轮换操作,并且 的范围导致无法依次枚举所有操作的顺序,所以这题需要使用在处理轮换操作时经常用的倍长数组法。
倍长数组法就是指通过将数组长度扩为原来的 倍(或 倍减 )从而包括所有轮换的排列,例如:
原数组:
扩倍后:

其中红线为轮换后排列。
对于二维数组也是一样,只不过需要把横长度和竖长度都扩倍:


其中 表示原二维数组。(其实只用开到图中黑线就行了,因为从第 列到第 列与从第 列到第 列保存的数据相同,少开一列省空间但没啥区别,每行也同理。)
接下来看怎么统计便于观察的方块数量。
这题要快速查询范围,因为我们要枚举每个格子的情况,已经要循环 次了,为了不见到那个乌黑的 TLE, 我们对于每次循环都要用 的复杂度查询。而这个特点恰好符合前缀和的特性,所以在这里使用类似二维前缀和的做法完成此题。
定义数组 : 表示以第 行第 列为左上角,以第 行第 列为右下角的矩阵中便于观察的方块组合的数量。
在预处理 数组时,对于 ,判断以第 行第 列为左上角,以第 行第 列为右下角的矩阵是否是一个便于观察的方块组合,如果是则初始化为 ,否则为 。
最终的答案为所有 中下面式子的最大值,其实就是二维前缀和的模板:
Code:
CPP#include <bits/stdc++.h>
using namespace std;
int n,m,a[2005][2005],s[2005][2005],maxx=-1;
char c;
void ctrl_cv(int x,int y,int f){//扩倍
for(int i=1;i<=x;i++){
for(int j=1;j<=y;j++){
if(f==1)a[n+i][j]=a[i][j];//复制到下面
if(f==2)a[i][m+j]=a[i][j];//复制到右面
if(f==3)a[n+i][m+j]=a[i][j];//复制到右下面
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>c;
if(c=='1')a[i][j]=1;
else a[i][j]=2;
}
}
ctrl_cv(n-1,m,1);//复制矩阵a,向下
ctrl_cv(n,m-1,2);//复制矩阵a,向右
ctrl_cv(n-1,m-1,3);//复制矩阵a,向右下
for(int i=2;i<2*n;i++){
for(int j=2;j<2*m;j++){
if((a[i-1][j-1]==a[i-1][j])&&(a[i-1][j-1]==a[i][j-1])&&(a[i][j-1]==a[i][j])&&(a[i-1][j]==a[i][j])){
s[i][j]=1;
}
}
}
//更新s数组
for(int i=2;i<2*n;i++){
for(int j=2;j<2*m;j++){
s[i][j]+=s[i][j-1];
}
}
for(int i=2;i<2*n;i++){
for(int j=2;j<2*m;j++){
s[i][j]+=s[i-1][j];
}
}
for(int i=n;i<2*n;i++){
for(int j=m;j<2*m;j++){
maxx=max(maxx,s[i][j]+s[i-n+1][j-m+1]-s[i-n+1][j]-s[i][j-m+1]);//取答案
}
}
cout<<maxx;
return 0;
}
//矩阵可以复制,代码不能复制!--by Ace2012
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...