题目大意:
  一个n*m的格子上有b个障碍物,现在让你往上面放正方形(长宽在格线上)。问可以放多少种边长、位置不同的正方形?

思路:
  很容易想到一个O(n^3)的暴力:
  首先前缀和,然后枚举某一个顶点和正方形的边长,判断一下正方形里面是否为空,如果空,则为一种满足条件的答案。
  枚举边长可以改成二分,这样复杂度是O(n^2 log n)的。
  再考虑一个O(n^2)的动规:
  用f[i][j]保存以(i,j)为右下角顶点的正方形的个数,显然,如果(i-1,j)(i,j-1)(i-1,j-1)(i,j)上都没有障碍,那么f[i][j]=min(f[i-1][j],f[i][j-1],f[i-1][j-1])+1。
  正解是一个O(nb)的奇怪做法:
  首先对于障碍物按列再按行排序。
  枚举每一行,将在这一行上面的障碍物加入一个数组中。
  考虑下边界在当前行的极大化正方形,无非有以下两种情况:
    1.上边被顶到。
    2.左右两边被顶到。
  现在我们让每个障碍物“代表”被其约束的点,记录下行数比它大的左端点和右端点,这一过程可以用单调栈来求。
  最后分情况计算出符合条件的正方形个数即可。

 #include<stack>
#include<vector>
#include<cstdio>
#include<cctype>
#include<algorithm>
typedef long long int64;
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'';
while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
return x;
}
const int B=;
struct Point {
int x,y;
bool operator < (const Point &another) const {
if(y==another.y) return x>another.x;
return y<another.y;
}
};
std::vector<Point> a,p;
std::stack<int> q;
int l[B],r[B];
inline int calc(const int &x,const int &y) {
if(!x) return ;
return (int64)(y*-std::min(x,y))*(std::min(x,y)-)/;
}
int main() {
int n=getint(),m=getint(),b=getint();
for(register int i=;i<=b;i++) {
const int x=getint(),y=getint();
a.push_back((Point){x,y});
}
std::sort(a.begin(),a.end());
int64 ans=;
for(register int i=;i<=n;i++) {
p.clear();
p.push_back((Point){i,});
for(register unsigned j=;j<a.size();j++) {
if(a[j].x<=i) {
p.push_back(a[j]);
}
}
p.push_back((Point){i,m+});
while(!q.empty()) q.pop();
q.push();
for(register unsigned i=;i<p.size();i++) {
while(q.size()>&&p[q.top()].x<=p[i].x) q.pop();
l[i]=q.top();
q.push(i);
}
while(!q.empty()) q.pop();
q.push(p.size()-);
for(register unsigned i=p.size()-;i>;i--) {
while(q.size()>&&p[q.top()].x<p[i].x) q.pop();
r[i]=q.top();
q.push(i);
}
for(register unsigned j=;j<p.size();j++) {
ans+=calc(i,p[j].y-p[j-].y-);
}
for(register unsigned j=;j<p.size()-;j++) {
ans+=calc(i-p[j].x,p[r[j]].y-p[l[j]].y-)-calc(i-p[j].x,p[r[j]].y-p[j].y-)-calc(i-p[j].x,p[j].y-p[l[j]].y-);
}
}
printf("%lld\n",ans);
return ;
}

[BalkanOI2016]Lefkaritika的更多相关文章

  1. 『HGOI 20190917』Lefkaritika 题解 (DP)

    题目概述 一个$n \times m$的整点集.其中$q$个点被m被设置为不能访问. 问这个点集中含有多少个不同的正方形,满足不包含任何一个不能访问的点. 对于$50\%$的数据满足$1 \leq n ...

  2. [BalkanOI2016]Cruise

    题目大意: 平面直角坐标系内有n个点,每个点有一个点权. 你从原点p出发,走若干个点然后回到原点. 两个点之间只能笔直走,你的收获为你的路径围起来的区域内的所有店权和除以路径长度. 问最大收益. 思路 ...

随机推荐

  1. static class 和 non static class 的区别

    static class non static class 1.用static修饰的是内部类,此时这个 内部类变为静态内部类:对测试有用: 2.内部静态类不需要有指向外部类的引用: 3.静态类只能访问 ...

  2. uboot makefile构建分析

    前言 几年前分析过uboot的构建及启动过程,做了笔记,但最终没有转为文章.这次又有机会开发嵌入式产品了(之前一年多都是在搞x86 linux),看了下uboot的构建过程,觉得有必要写下整个分析过程 ...

  3. Linux 入门记录:十九、Linux 包管理工具 RPM

    一.源代码管理 绝大多数开源软件都是直接以源代码形式发布的,一般会被打包为 tar.gz 的归档压缩文件.程序源代码需要编译为二进制可执行文件后才能够运行使用.源代码的基本编译流程为: ./confi ...

  4. Sqlserver获取所有数据库名,表信息,字段信息,主键信息,以及表结构等。

    --获取所有数据库名: SELECT name FROM master..sysdatabases WHERE name NOT IN ( 'master', 'model', 'msdb', 'te ...

  5. RSA加密解密与加签验签

    RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的.1987年7月首次在美国公布 ...

  6. python_day6学习笔记

    一.Logger模块 logging.basicConfig函数 可通过具体参数来更改logging模块默认行为,可用参数有 filename: 用指定的文件名创建FiledHandler(后边会具体 ...

  7. 如何简单解释 MapReduce算法

    原文地址:如何简单解释 MapReduce 算法 在Hackbright做导师期间,我被要求向技术背景有限的学生解释MapReduce算法,于是我想出了一个有趣的例子,用以阐释它是如何工作的. 例子 ...

  8. Guice2.0的变化——第一部分 新的特性(上)

    http://superleo.iteye.com/blog/314816 Private Modules PrivateModules 用于创建并不需要对外可见的绑定对象.当然,这样会使得封装变得更 ...

  9. LeetCode解题报告—— Jump Game & Merge Intervals & Permutation Sequence

    1. Jump Game Given an array of non-negative integers, you are initially positioned at the first inde ...

  10. hdu 1087(LIS变形)

    Super Jumping! Jumping! Jumping! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 ...