【简解】C2CRNI - Crni
【题目大意】
给定一个N行N列的矩阵,每个格子要么为白色要么为黑色。黑矩形为所涵单元格数大于等于2且所涵单元格均为黑色的矩表。要解决的问题是在给定的矩形中找出两个没有共公部分的黑矩形,输出所有方案数,由于数较大,输出它对10007的余数。
传送门。
【分析】
听说是道很老的套路题,考试考了这道。。。
有个比较明显的东西,就是我们要求的两个黑矩形没有公共部分,那么必然会有一条竖线(或横线)把这两个黑矩形分开,我们就可以枚举这条竖线(横线)来统计答案。
为了避免计算重复,我们需要一边固定,另一边统计总和。并且,还应减去既能被一条竖线分开又能被一条横线分开的两个黑矩形(因为它被算了两次嘛)。
大体思路就是这样,然后就是实现。
比较容易想到的就是计算以每个格子为左下角(右下角、左上角、右上角)的黑矩形有多少个。
考试的时候太弱了,只会写\(O(n^4)\)的暴力。。。(它还挂了)
简单说一点暴力吧,就是\(O(n^2)\)枚举每个格子,然后\(O(n^2)\)枚举矩形的长度,可以用二维前缀和\(O(1)\)来判断枚举的矩形是否合法,然后就\(O(n^4)\)预处理,再\(O(n^2)\)统计贡献。
可以看到,预处理是瓶颈,我们应考虑如何优化预处理的复杂度。
对每一行拆开考虑,我们会发现比较像直方图里的最大矩形,然后就做啊。
我们以计算以每个格子为右下角的黑矩形有多少个为例。
设\(f[i][j]\)就是以\((i,j)\)为右下角的黑矩形有多少个,我们会发现,它可以直接继承它前面出现的第一个小于它高度的位置的答案,那中间那些比它还高的矩形呢,没错,只能扩展它自己的高度。
即\(f[i][j]=f[i][k]+1+h[j]*(j-k)-1\)
其中\(k\)表示从\(j\)向前走第一次出现的\(h[k]<h[j]\)的位置,那么直接可以继承\(f[i][k]\),然后加一,然后对于那块大的矩形里的所有点均可作为当前矩形的左上角,除了自己本身,因为\(1\times 1\)的黑矩形不能算入答案,所以会减一。
考虑到\(k\)的计算,想到单调栈优化,可以做到\(O(1)\)转移。
所以我们做到了\(O(n^2)\)预处理,然后就行了。
细节有点多,还有要注意时刻取模。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
const int P = 10007;
const int N = 1000 + 5;
inline int read(){
int f = 1, x = 0; char ch;
do { ch = getchar(); if (ch == '-') f = -1; } while (ch < '0' || ch > '9');
do {x = (x << 3) + (x << 1) + ch - '0'; ch = getchar(); } while (ch >= '0' && ch <= '9');
return f * x;
}
inline void hand_in() {
freopen("crni.in", "r", stdin);
freopen("crni.out", "w", stdout);
}
int n, mp[N][N], res;
int f[N][N], g[N][N], h[N];
char ch[N][N]; int sta[N], top;
int main(){
// hand_in();
n = read();
for (int i = 1;i <= n; ++i) scanf("%s", ch[i] + 1);
for (int i = 1;i <= n; ++i) {
for (int j = 1;j <= n; ++j) {
mp[i][j] = (ch[i][j] == 'C');
}
}
// 左上
memset(h, 0, sizeof h);
for (int i = 1;i <= n; ++i) {
top = 0;
sta[top] = 0;
for (int j = 1;j <= n; ++j) {
if (mp[i][j] == 1) h[j] ++;
else h[j] = 0;
if (h[j] == 0) {
top = 0;
sta[top] = j;
continue;
}
int size;
while (top && h[sta[top]] >= h[j]) top --;
size = h[j] * (j - sta[top]) - 1;
f[i][j] = f[i][sta[top]] + size + (top > 0);
f[i][j] %= P;
sta[++top] = j;
}
}
//右下
memset(h, 0, sizeof h);
for (int i = n;i >= 1; --i) {
top = 0;
sta[top] = n + 1;
for (int j = n;j >= 1; --j) {
if (mp[i][j] == 1) h[j] ++;
else h[j] = 0;
if (h[j] == 0) {
top = 0;
sta[top] = j;
continue;
}
int size;
while (top && h[sta[top]] >= h[j]) top --;
size = h[j] * (sta[top] - j) - 1;
g[i][j] = g[i][sta[top]] + size + (top > 0);
g[i][j] %= P;
sta[++top] = j;
}
}
int suma = 0, sumb = 0;
for (int i = 1;i < n; ++i) {
for (int j = 1;j <= n; ++j) {
suma += f[i][j], sumb += g[i + 1][j];
suma %= P, sumb %= P;
}
res += suma * sumb;
res %= P;
sumb = 0;
}
suma = 0, sumb = 0;
for (int j = 1;j < n; ++j) {
for (int i = 1;i <= n; ++i) {
suma += f[i][j], sumb += g[i][j + 1];
suma %= P, sumb %= P;
}
res += suma * sumb;
res %= P;
sumb = 0;
}
for (int i = 1;i <= n; ++i) {
for (int j = 1;j <= n; ++j) {
f[i][j] += f[i - 1][j] + f[i][j - 1] - f[i - 1][j - 1] + P;
f[i][j] %= P;
}
}
for (int i = 1;i < n; ++i) {
for (int j = 1;j < n; ++j) {
res -= (f[i][j] * g[i + 1][j + 1] + P) % P;
while (res < 0) res += P;
}
}
//右上
memset(f, 0, sizeof f);
memset(h, 0, sizeof h);
for (int i = 1;i <= n; ++i) {
top = 0;
sta[top] = n + 1;
for (int j = n;j >= 1; --j) {
if (mp[i][j] == 1) h[j] ++;
else h[j] = 0;
if (h[j] == 0) {
top = 0;
sta[top] = j;
continue;
}
int size;
while (top && h[sta[top]] >= h[j]) top --;
size = h[j] * (sta[top] - j) - 1;
f[i][j] = f[i][sta[top]] + size + (top > 0);
f[i][j] %= P;
sta[++top] = j;
}
}
//左下
memset(g, 0, sizeof g);
memset(h, 0, sizeof h);
for (int i = n;i >= 1; --i) {
top = 0;
sta[top] = 0;
for (int j = 1;j <= n; ++j) {
if (mp[i][j] == 1) h[j] ++;
else h[j] = 0;
if (h[j] == 0) {
top = 0;
sta[top] = j;
continue;
}
int size;
while (top && h[sta[top]] >= h[j]) top --;
size = h[j] * (j - sta[top]) - 1;
g[i][j] = g[i][sta[top]] + size + (top > 0);
g[i][j] %= P;
sta[++top] = j;
}
}
for (int i = 1;i <= n; ++i) {
for (int j = n;j >= 1; --j) {
f[i][j] += f[i - 1][j] + f[i][j + 1] - f[i - 1][j + 1] + P;
f[i][j] %= P;
}
}
for (int i = 1;i < n; ++i) {
for (int j = 2;j <= n; ++j) {
res -= (f[i][j] * g[i + 1][j - 1] + P) % P;
while (res < 0) res += P;
}
}
printf("%d", res);
return 0;
}
【简解】C2CRNI - Crni的更多相关文章
- python ConfigParser、shutil、subprocess、ElementTree模块简解
ConfigParser 模块 一.ConfigParser简介ConfigParser 是用来读取配置文件的包.配置文件的格式如下:中括号“[ ]”内包含的为section.section 下面为类 ...
- 【题解】C2Crni - Crni [COCI2010] [SP7884]
[题解]C2Crni - Crni [COCI2010] [SP7884] 传送门:\(\text{C2Crni - Crni}\) \(\text{[COCI2010]}\) \(\text{[SP ...
- AC题目简解-数据结构
A - Japan POJ 3067 要两条路有交叉,(x1,y1)(x2,y2)那么需要满足:(x1-x2)*(y1-y2)<0判断出这是求逆序的问题 树状数组求逆序,先通过自定义的比较器实 ...
- UE4 RHI与Render模块简解
UE4中的RHI指的是Render hardware interface,作用像Ogre里的RenderSystem,针对Dx11,Dx12,Opengl等等平台抽象出相同的接口,我们能方便能使用相同 ...
- zabbix基本监控各指标简解
监控项目及使用模板 监控http和https: Template App HTTP Service Template App HTTPS Service 监控cpu,内存,网络等: Templ ...
- (转)FFMPEG解码H264拼帧简解
http://blog.csdn.net/ikevin/article/details/7649095 H264的I帧通常 0x00 0x00 0x00 0x01 0x67 开始,到下一个帧头开始之前 ...
- Spring ApplicationContext 简解
ApplicationContext是对BeanFactory的扩展,实现BeanFactory的所有功能,并添加了事件传播,国际化,资源文件处理等. configure locations:(C ...
- HTTP协议简解
1.什么是http协议 http协议: 浏览器客户端 与 服务器端 之间数据传输的规范 2.查看http协议的工具 1)使用火狐的firebug插件(右键->查看元素->网络) 2)使用 ...
- linux netstat 命令简解
Netstat 简介: Netstat是在内核中访问网络及相关信息的程序,它能提供TCP连接,TCP和UDP监听,进程内存管理的相关报告.常见参数-a (all)显示所有选项,默认不显示LISTEN相 ...
随机推荐
- Kubeasz部署K8s基础测试环境简介
下面介绍使用Kubeasz部署K8s集群环境. https://github.com/easzlab/kubeasz在需要使用kubeeasz项目安装的k8s时,需要将所有需要它来部署的节点上,都安装 ...
- GoCN每日新闻(2019-11-10)
GoCN每日新闻(2019-11-10) 1. Go Netpoll I/O多路复用构建原生网络模型之源码深度解析 https://taohuawu.club/go-netpoll-io-multip ...
- Zabbix实战-简易教程--中间件RabbitMQ监控
一.环境 zabbix版本:3.0 二.脚本说明 .├── rabbitmq.template.xml 模板文件├── scripts │ └── rabbitmq│ ├── api.p ...
- c# 画正态分布图
/// <summary> /// 提供正态分布的数据和图片 /// </summary> public class StandardDistribution { /// &l ...
- 【Beta】Scrum Meeting 8
前言 Beta阶段第8次会议在5月13日22:00由PM在大运村一公寓三层召开, 时长30min. 任务分配 姓名 今日任务 明日任务 困难 周博闻 修复修改密码问题#54 添加主页公告栏 #57实现 ...
- [技术博客]django连接mysql数据库的方法及部分问题的解决方法
配置机器介绍 操作系统:Ubuntu 18.04.2 LTS 64位 python版本:Python 3.6.7 Django版本:Django 2.2 MySql版本:5.7.26 数据库选择 我们 ...
- 后台启动es head,关闭shell后es head自动关闭
后台启动head命令:grunt server & 注意:加上&虽然执行了后台启动,但还是有日志打印出来,使用ctrl+c可以退出.这时如果直接关闭shell, head进程就会终止 ...
- arcpy地理处理工具案例教程-生成范围-自动画框-深度学习样本提取-人工智能-AI
arcpy地理处理工具案例教程-生成范围-自动画框-深度学习样本提取-人工智能-AI 商务合作,科技咨询,版权转让:向日葵,135-4855_4328,xiexiaokui#qq.com 目的:对面. ...
- Linux虚拟机:发布WebService接口出现异常,无法访问接口
Linux虚拟机:发布WebService接口出现异常,无法访问接口 今天在部署WebService工程的时候遇到的问题: 在Linux虚拟机上部署一个tomcat同时在tomcat下放置2个工程,其 ...
- 从 SVN 迁移至 Git 并保留所有 commit 记录
yum install -y git-svn 用户映射文件user.txt,等号左边为svn账号,右边为Git用户名和邮箱.注意:svn中有多少用户就要映射多少 test1=test1<1472 ...