题目链接

问题描述

一个棋盘有n条横线,m条竖线,上面有k个黑点,问有多少个不包含黑点的矩形。

数据范围:

n和m最大为1000,k最大为10

方法一:动态规划

复杂度n*m*k

import java.awt.Point;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner; public class Main {
int n, m;
long dp[][];
List<Point> black; long solve() {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
int now = 0;//now表示以i,j这个点为右下角的矩形的个数
int lastX = 0;
int lastY = j;
for (int k = black.size() - 1; k >= -1; k--) {
//此处哨兵单元设计很巧妙,让k==-1的时候自动启用哨兵单元
Point p;
if (k == -1) p = new Point(i, 0);
else p = black.get(k);
if (p.y > j) continue;
if (p.x > i || p.x < lastX) continue;
now += (i - lastX) * (lastY - p.y);
lastX = p.x;
lastY = p.y;
}
dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + now;
}
}
return dp[n][m];
} Main() {
Scanner cin = new Scanner(System.in);
n = cin.nextInt();
m = cin.nextInt();
dp = new long[n + 1][m + 1];
black = new LinkedList<>();
int k = cin.nextInt();
while (k-- > 0) {
int r = cin.nextInt(), c = cin.nextInt();
black.add(new Point(r, c));
}
//对全部点进行排序(按照列从小到大进行排序)
black.sort(Comparator.comparing(x -> x.y));
for (int i = 0; i <= n; i++) dp[i][0] = 0;
for (int i = 0; i <= m; i++) dp[0][i] = 0;
long ans = solve();
System.out.println(ans);
} public static void main(String[] args) {
new Main();
}
}

可以通过“缩点”法降低复杂度。

方法二:容斥原理

10个点有1024种情况,判断每种情况是否合理,然后统计个数即可。

复杂度之和k有关,跟n、m无关。

相似问题

codeforce上有一道规模更大的题,n和m为10000,k为20:

http://codeforces.com/gym/101350/problem/G

51nod

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1291

#include<bits/stdc++.h>
using namespace std;
#define st first
#define nd second
#define rep(i, a, b) for(int i=(a); i<(b); i++)
#define sz(x) (int)x.size()
#define de(x) cout<< #x<<" = "<<x<<endl
#define dd(x) cout<< #x<<" = "<<x<<" "
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi; const int N = 666;
int n, m, top;
int u[N], sta[N];
ll c[N][N];
char s[N]; int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%s", s+1);
for(int j = 1; j <= m; j++)
u[j] = (s[j] == '1')? u[j]+1: 0;
top = 0;
sta[top++]=0;
for(int j = 1; j <= m+1; j++) {
while(u[sta[top-1]] > u[j]) {
++c[max(u[sta[top-2]], u[j])+1][j-sta[top-2]-1];//维护单调上升的栈, 看每个柱块向左和向右的最大延伸距离, 即为宽度
--c[u[sta[top-1]]+1][j-sta[top-2]-1]; //枚举i为底边, 对高度范围为[max(u[sta[top-2]],u[j])+1, u[sta[top-1]]], 宽度为j-sta[top-2]-1的矩形加1
--top;
}
while(top && u[sta[top-1]] == u[j]) --top;
sta[top++] = j;
}
}
for(int i = 2; i <= n; i++) for(int j = 1; j <= m; j++) c[i][j] += c[i-1][j]; //c1[i, j]: 高为i (n^2) 的连通块, 只统计最长宽度的。
for(int i = 1; i <= n; i++) {
for(int j = m-1; j; j--) c[i][j] += c[i][j+1]; //c2[i, j]: 高i宽 >= j的连通块的个数
for(int j = m-1; j; j--) c[i][j] += c[i][j+1]; //c3[i, j]: 高i宽j的全1矩阵的个数
}
for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) printf("%lld%c", c[i][j], " \n"[j == m]);
return 0;
}
/*
3 3
011
110
110
如何得到c1? 暴力的话, c1是枚举n^2的上下边界, 优化后, 变成枚举直方图的最底边,快速统计各个不同的上顶边。这个可以通过单调栈+差分解决。求前缀和后就得到c1。
总的时间复杂度为O(nm).
c1
0 3 0
1 1 0
1 0 0
c2
3 3 0
2 1 0
1 0 0
c3
6 3 0
3 1 0
1 0 0 */

leetcode

https://www.nowcoder.com/acm/contest/79/D

#include<bits/stdc++.h>
using namespace std;
#define st first
#define nd second
typedef long long ll;
const int mod = 1e9+7;
pair<int, int> s[5111];
int main() {
int n, m, c;
scanf("%d%d%d", &n, &m, &c);
for(int i = 1, x, y; i <= c; i++) scanf("%d%d", &x, &y), s[i] = {x, y};
sort(s+1, s+c+1);
long long ans = 0;
for(int i = 1; i <= c; i++){
int l = 0, r = m+1;
for(int j = i-1; ~j; j--){ //从下往上从左往右枚举之前的点
ans += (r-s[i].nd)*(n-s[i].st+1LL)%mod*(s[j+1].st-s[j].st)%mod*(s[i].nd-l)%mod; //上边界为s[j].st ~ s[j+1].st
ans %= mod;
if(s[j].nd > s[i].nd) r = min(r, s[j].nd);
if(s[j].nd < s[i].nd) l = max(l, s[j].nd);
}
}
//n*m矩阵的子矩阵个数 = 左右两边界 * 上下两边界
long long cnt = (n*(n+1LL)/2%mod)*(m*(m+1LL)/2%mod)%mod;
ans = (cnt-ans)%mod;
if(ans < 0) ans += mod;
printf("%lld\n", ans);
return 0;
}

参考资料

https://www.cnblogs.com/dirge/p/10034268.html

hihocoder234周 计算不包含黑点的矩形个数的更多相关文章

  1. 【Java】一个小程序,计算它包含的代码所需的耗时

    写一个小程序,用来计算它包含的代码所需的耗时.虽然简单,测试代码是否耗时还是有点用的,不用重新写嘛~ import java.util.Date; import java.util.concurren ...

  2. 计算1到N中包含数字1的个数

    转自:http://pandonix.iteye.com/blog/204840 Mark N为正整数,计算从1到N的所有整数中包含数字1的个数.比如,N=10,从1,2...10,包含有2个数字1. ...

  3. hdu2524 (求矩形个数,水题。。。)

    hdu 2524 N - 暴力求解.打表 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64 ...

  4. Java实现 LeetCode 315 计算右侧小于当前元素的个数

    315. 计算右侧小于当前元素的个数 给定一个整数数组 nums,按要求返回一个新数组 counts.数组 counts 有该性质: counts[i] 的值是 nums[i] 右侧小于 nums[i ...

  5. 计算阶乘n!末尾0的个数

    一.问题描述 给定一个正整数n,请计算n的阶乘n!末尾所含有“0”的个数.例如: 5!=120,其末尾所含有的“0”的个数为1: 10!= 3628800,其末尾所含有的“0”的个数为2: 20!= ...

  6. 基于visual Studio2013解决面试题之0410计算二进制中1的个数

     题目

  7. Java:判断字符串中包含某字符的个数

    Java:判断字符串中包含某字符的个数 JAVA中查询一个词在内容中出现的次数: public int getCount(String str,String key){ if(str == null ...

  8. Leetcode 357.计算各个位数不同的数字个数

    计算各个位数不同的数字个数 给定一个非负整数 n,计算各位数字都不同的数字 x 的个数,其中 0 ≤ x < 10n . 示例: 输入: 2 输出: 91 解释: 答案应为除去 11,22,33 ...

  9. Leetcode 315.计算右侧小于当前元素的个数

    计算右侧小于当前元素的个数 给定一个整数数组 nums,按要求返回一个新数组 counts.数组 counts 有该性质: counts[i] 的值是  nums[i] 右侧小于 nums[i] 的元 ...

随机推荐

  1. SQL SERVER 的用户数,连接,连接池 license

    SQL SERVER 理论上有32767个逻辑连接,SQL SERVER根据系统自行调配连接池. 首先 ,操作系统的用户数:即同时通过网络连接到这台电脑上面的用户限制,以5用户操作系统,搭建的文件服务 ...

  2. [Math]理解卡尔曼滤波器 (Understanding Kalman Filter) zz

    1. 卡尔曼滤波器介绍 卡尔曼滤波器的介绍, 见 Wiki 这篇文章主要是翻译了 Understanding the Basis of the Kalman Filter Via a Simple a ...

  3. Nginx网站常见的跳转配置实例

    相信大家在日常运维工作中如果你用到nginx作为前端反向代理服务器的话,你会对nginx的rewrite又爱又恨,爱它是因为你搞定了它,完成了开发人员的跳转需求后你会觉得很爽,觉得真的很强大,恨它是因 ...

  4. ssh tunnel

    https://peppoj.net/2012/10/tunnel-http-traffic-encrypted-using-polipo-and-ssh/ --------------------- ...

  5. 解决Ubuntu/debian的Apt-get 由于依赖关系安装失败的问题

    The following packages have unmet dependencies: libssl-dev: Depends: libssl0.9.8 (= 0.9.8k-7ubuntu8) ...

  6. 跨域资源共享(CORS)--跨域ajax

    几年前,网站开发者都因为ajax的同源策略而撞了南墙.当我们惊叹于XMLHttpRequest对象跨浏览器支持所带来的巨大进步时,我们很快发现没有一个方法可以使我们用JavaScript实现请求跨域访 ...

  7. 页面显示This is the initial start page for the WebDriver server.的解决办法

    今天在做项目的时候,遇到一个奇怪的问题,打开浏览器是正常的,但是页面不会跳转到需要的URL,而是提示一行白字,如图: 反复研究了脚本,没有问题啊,但是就是不跳转. 后来查了下,在某论坛上找到了答案: ...

  8. CentOS7安装 Apache HTTP 服务器

    CentOS7安装 Apache HTTP 服务器 时间:2015-05-02 00:45来源:linux.cn 作者:linux.cn 举报 点击:11457次 不管你因为什么原因使用服务器,大部分 ...

  9. Redis 操作数据

    展现最新数据 Web应用常常要展现最新数据,就会根据时间对数据排序: SELECT * FROM foo WHERE ... ORDER BY time DESC LIMIT 10 随着数据的增加,问 ...

  10. HOW TO: Synchronize changes when completing a P2V or V2V with VMware vCenter Converter Standalone 5.1

    http://www.experts-exchange.com/Software/VMWare/A_11489-HOW-TO-Synchronize-changes-when-completing-a ...