题目大意:
  一个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. js中的for in 循环

    1.数组 使用for in 遍历数组时,其索引被视为对象的属性,从而直接输出数组的索引 var arr = ["a","b","c"]; f ...

  2. mysql where/having区别

    mysql> select 2-1 as a,password from mysql.user where user='root' having a>0; +---+----------- ...

  3. vmware安装ubuntu " Intel VT-x 处于禁用状态"

    vmware安装ubuntu " Intel VT-x 处于禁用状态" http://jingyan.baidu.com/article/fc07f98976710e12ffe51 ...

  4. 448D - Codeforces

    D. Multiplication Table time limit per test 1 second memory limit per test 256 megabytes Bizon the C ...

  5. MediaWiki安装配置(Linux)【转】

    转自:http://blog.csdn.net/gao36951/article/details/43965527 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] 1Media ...

  6. OC 07 类的扩展

    1.NSDate的使用 NSDate是Cocoa中⽤于处理⽇期和时间的基础类,封装了某⼀给定的时刻(含日期,时间,时区) 注意NSLog(@“%@”,nowDate);⽆论你是哪个时区的时间,打印时总 ...

  7. MyEclipse/Eclipse安装插件的几种方式

    众所周知MyEclipse是一个很强大的Java IDE,而且它有许多开源免费又好用的插件,这些插件给我们开发过程中带来了许多方便.插件具有针对性,例如,你如果做安卓开发,可能需要一个ADT(Andr ...

  8. js获取鼠标的位置

    <!doctype html><html><head><meta charset="utf-8"><title>获取鼠标 ...

  9. eclipse 配置jsp

    1.安装jdk和jre 下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html ...

  10. php设计模式四 ---- 原型模式

    1.简介 用于创建重复的对象,同时又能保证性能.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式 意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 主要解决:在运 ...