gmoj 6860. 【2020.11.14提高组模拟】鬼渊传说
题目
Time Limits: 1000 ms
Memory Limits: 518400 KB
简要题意
给出一个网格图,每个格子有黑白二色,求有多少个子矩形满足将其挖出来后恰好有一个黑色四连通块且不存在由白色格子组成的空腔。
空腔:某个白色格子在空腔内当且仅当其不能通过上下左右四方向走到边界。
输入
第一行两个数n,mn,mn,m,表示网格图的大小。
接下来 n 行每行一个长为 m 的 01 串,表示网格图的颜色情况(0 为白 1 为黑)
输出
一行一个数表示答案。
样例 1 输入
4 4
1111
1101
1001
1111
样例 1 输出
83
数据规模与约定
对于 100% 数据满足0<n,m≤3000<n,m\le 3000<n,m≤300。
数据点编号 | n≤n\len≤ | m≤m\lem≤ | 特殊性质 |
---|---|---|---|
1,2 | 5 | 5 | |
3,4 | 20 | 20 | |
5,6 | 300 | 300 | 保证没有两个黑色格子相邻 |
7,8 | 300 | 300 | 保证任意子矩形不存在空腔 |
9,10 | 300 | 300 |
题解
考场上想到可以通过搜索白色连通块得到包含空腔的最小矩形,但是其它都没有想到。
看到n,m≤300n,m\le 300n,m≤300,容易想到要用O(n3)O\left(n^3\right)O(n3)的方法做(这里的n,mn,mn,m同阶,因此可以这样写,下同)。一个很简单的思路就是依次枚举子矩形的上、下、左边界,看一下有多少个合法的右边界。
分析一下题目,发现这道题有2个难点:一是子矩形中有且仅有一个黑色连通块,二是子矩形不包含含有空腔的最小矩形。
第一个——有且仅有一个黑色连通块的子矩形
令E,F,V,XE,F,V,XE,F,V,X分别表示子矩形中连接两个'1'
的边的数量、由'1'
组成的简单四元环的数量、'1'
的数量、连通块的数量。由欧拉定理,可得V−E+F=XV-E+F=XV−E+F=X
E,F,VE,F,VE,F,V都是可以用前缀和维护得出的。
具体来说,可以设hori,veri,nodei,squihor_i ,ver_i ,node_i ,squ_ihori,veri,nodei,squi分别表示这样的图形数量(顶点都表示'1'
):
那么当选择了[l,r][l,r][l,r]中所有列时,有E=∑i=lr−1hori+∑i=lrveri,V=∑i=lrnodei,F=∑i=1r−1squi\begin{aligned} E&=\sum_{i=l}^{r-1}hor_i +\sum_{i=l}^r ver_i ,\\[2ex] V&=\sum_{i=l}^r node_i ,\\[2ex] F&=\sum_{i=1}^{r-1} squ_i \end{aligned}EVF=i=l∑r−1hori+i=l∑rveri,=i=l∑rnodei,=i=1∑r−1squi
这些∑\sum∑又可以用前缀和来处理。
但是对于一个已知的lll,怎么快速求出一个区间内有多少个rrr使得V−E+F=1V-E+F=1V−E+F=1呢?
令E0=∑i=1l−1(hori+veri),E1=verr+∑i=1r−1(hori+veri)E_0 =\sum_{i=1}^{l-1} (hor_i+ver_i),E_1=ver_r + \sum_{i=1}^{r-1} (hor_i+ver_i)E0=∑i=1l−1(hori+veri),E1=verr+∑i=1r−1(hori+veri),其它V0,V1,F0,F1V_0 ,V_1 ,F_0 ,F_1V0,V1,F0,F1也是同理。
那么可以通过移项把等号的左边变成没有下标111的,右边变成没有下标000的。
用一个桶就可以处理了,注意移项后有可能等号两边都为负数,而且桶很大不能每次都memset
。
第二个——不包含含有空腔的最小矩形的子矩形。
令上边界、下边界、左边界分别为i,j,ki,j,ki,j,k。
可以把所有的含有空腔的最小矩形都用数据结构挂在它的下边界处,当 jjj 扫到它时,对于一个上边界大于等于 iii 的矩形,令其左边界为lll,右边界为rrr,它会限制在[1,l][1,l][1,l]中的kkk。这些kkk所对应的右边界不能超过r−1r-1r−1。
只要把右边界的限制挂在lll上,从右往左枚举kkk就行了。
这道题的细节相对来说比较少。
CODE
#include<cstdio>
#include<cstring>
using namespace std;
#define M 90005
#define N 305
const int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
struct area{int up,left,right,nex;}a[M];
int hor[N],ver[N],squ[N],node[N],_h[N],_v[N],_s[N],_n[N],fir[N],lim[N],b[200005];
int time[200005],n,m,x1,y1,x2,y2,cnt,T;
char s[N][N];bool vis[N][N];
void dfs(int x,int y)
{vis[x][y]=1;if(x1>x) x1=x;if(x2<x) x2=x;if(y1>y) y1=y;if(y2<y) y2=y;for(int i=0,xx,yy;i<4;++i){xx=x+dx[i],yy=y+dy[i];if(xx&&yy&&xx<=n&&yy<=m&&s[xx][yy]=='0'&&!vis[xx][yy])dfs(xx,yy);}
}
inline void add(int x,int y)
{if(x<0) puts("dd");if(time[x]<T) time[x]=T,b[x]=y;else b[x]+=y;
}
inline int qry(int x){return time[x]<T?0:b[x];}
int main()
{freopen("village.in","r",stdin);freopen("village.out","w",stdout);long long ans=0;scanf("%d%d",&n,&m);for(int i=1;i<=n;++i) scanf("%s",s[i]+1);for(int i=1;i<=n;++i) for(int j=1;j<=m;++j)if(s[i][j]=='0'&&!vis[i][j]){x1=y1=N,x2=y2=0,dfs(i,j),--x1,--y1,++x2,++y2;if(x1&&y1&&x2<=n&&y2<=m) a[++cnt]=(area){x1,y1,y2,fir[x2]},fir[x2]=cnt;}for(int up=1;up<=n;++up){memset(lim,0x3f,sizeof lim);memset(hor,0,sizeof hor);memset(ver,0,sizeof ver);memset(squ,0,sizeof squ);memset(node,0,sizeof node);for(int down=up;down<=n;++down){for(int i=1;i<=m;++i) if(s[down][i]=='1'){hor[i]+=s[down][i+1]=='1';if(up<down)ver[i]+=s[down-1][i]=='1',squ[i]+=s[down-1][i]=='1'&&s[down-1][i+1]=='1'&&s[down][i+1]=='1';++node[i];}for(int i=1;i<=m;++i)_h[i]=_h[i-1]+hor[i],_v[i]=_v[i-1]+ver[i],_s[i]=_s[i-1]+squ[i],_n[i]=_n[i-1]+node[i];for(int i=fir[down];i;i=a[i].nex) if(a[i].up>=up)if(lim[a[i].left]>a[i].right-1) lim[a[i].left]=a[i].right-1;++T;for(int l=m,r=m;l;--l){//E=_h[r-1]-_h[l-1]+_v[r]-_v[l-1],V=_n[r]-_n[l-1],F=_s[r-1]-_s[l-1];add(M+1+_h[l-1]+_v[l]-_n[l]-_s[l-1],1);if(r>lim[l]){while(r>lim[l])add(M+1+_h[r-1]+_v[r]-_n[r]-_s[r-1],-1),--r;}if(l<=r){ans+=qry(M+_h[l-1]+_v[l-1]-_n[l-1]-_s[l-1]);
// printf("(%d,%d)\t(%d,%d):\n",up,l,down,r);
// for(int i=up;i<=down;++i,puts(""))
// for(int j=l;j<=r;++j) printf("%c",s[i][j]);
// puts("");}}}}printf("%lld\n",ans);return 0;
}
gmoj 6860. 【2020.11.14提高组模拟】鬼渊传说相关推荐
- 6848. 【2020.11.03提高组模拟】融入社会的计划
Description Input Output 一行一个整数表示答案. upd: 无解输出-1. Sample Input Sample Input1 6 6 13 11 1 1 4 5 5 Sa ...
- 6846. 【2020.11.02提高组模拟】旅人1970
Description Input Output Sample Input Sample Input1 25 4 4 1 2 3 2 1 1 1 2 Sample Output Sample Outp ...
- 【2020.11.30提高组模拟】剪辣椒(chilli)
剪辣椒(chilli) 题目描述 在花园里劳累了一上午之后,你决定用自己种的干辣椒奖励自己. 你有n个辣椒,这些辣椒用n-1条绳子连接在一起,任意两个辣椒通过用若干个绳子相连,即形成一棵树. 你决定分 ...
- JZOJ6893. 【2020.11.25提高组模拟】小 T 与灵石(stone)题解
这道题需要转化,换根和卡常. 首先将集合中的点拉出来,找它们的直径 不需要什么虚树,随便挑一个集合里的点为根,做一遍dfs,找最远点x(要在集合里),以x为根重复以上操作,找到最远点y,x-y就是题解 ...
- 【2020.12.03提高组模拟】袋鼠
题目 题目描述 你知道吗?乌拉圭的人口有345.7万,同时,仅澳大利亚就有4700万只袋鼠. 袋鼠决定入侵乌拉圭.袋鼠们将在平原上布阵,平原被划分成 n×mn \times mn×m 的网格. 每个格 ...
- JZOJ6828. 【2020.10.25提高组模拟】幂
Description TTT组数据,T≤1e5,n≤1e7T\le1e5,n\le1e7T≤1e5,n≤1e7 Solution 好家伙,最下面的数据范围居然是这样的: 直接以为卡特兰数乘上个组合数 ...
- 【二分,找规律】Day 14 提高组模拟C组 T1 小麦亩产一千八
题目大意 给定斐波那契的第aaa项,求出第b" role="presentation">bbb项,默认第0项为1 解题思路 方法一:递推 找到规律后O(b)O(b) ...
- 6810. 【2020.10.05提高组模拟】路哥
Description Input Output Sample Input Sample Input1 3 1 1 1 1 1 2 2 3 Sample Input2 9 4 0 0 1 4 1 2 ...
- 第一届『Citric杯』NOIP提高组模拟赛 题解
[官方题解]第一届『Citric杯』NOIP提高组模拟赛 题解 第一题 柠檬超市 这题是本次模拟赛的送分题.做法显然. 但是注意此题有一个陷阱: 注意W和C的规模都是10^9,所以如果直接用doubl ...
最新文章
- DELPHI 中 Window 消息大全使用详解
- 2021-10-14 yolov5踩坑!!!经验大赏
- Oracle.ManagedDataAccess.dll 连接Oracle数据库不需要安装客户端
- 表中查询重复的数据,如何通过sql语句查询?
- button按钮onclick触发不了_手把手教你深入CSS实现一个粒子动效的按钮
- telegraf output input 配置用法
- Android的Touch系统简介(一)
- u盘装linux7.2,u盘安装centos 7.2
- Scala程序将字符串转换为整数
- TFLite基础知识
- Swift学习笔记十二
- angelajs中ajax,前端测试数据怎么利用Mock.js进行生成
- 为什么要制定一些自己根本不想执行的计划?
- php添加开机启动脚本_php-fpm开机自动启动Shell脚本
- 国企转型----北京市供销社探索大数据之路!
- 简单小爬虫爬取招标信息
- 单片机编程语言——C语言(1)
- 卫星星历和历书的区别
- php 怎么判断是微信浏览器,php 判断是否为手机浏览器和微信浏览器
- 《菜根谭》 明·洪应明
热门文章
- 量化交易python入门书籍推荐_求量化投资入门书籍或课程推介。?
- cad打印黑白图纸,该如何打印呢?
- 【翻译】StreamDM:基于Spark Streaming的高级数据挖掘 StreamDM: Advanced Data Mining in Spark Streaming
- Lustre是开放源代码的集群文件系统
- 2014-04网易、微软、百度、腾讯、阿里实习生招聘经验与经过
- ubuntu/centos7.5安装python3.6
- 201412-1 门禁系统
- nao基于opencv的红球识别
- 卷闸门433遥控钥匙对拷方法
- 超声波塑料焊接发生器驱动电源设计