BZOJ.4558.[JLOI2016]方(计数 容斥)
图基本来自这儿。
看到这种计数问题考虑容斥。\(Ans=\) 没有限制的正方形个数 - 以\(i\)为顶点的正方形个数 + 以\(i,j\)为顶点的正方形个数 - 以\(i,j,k\)为顶点的正方形个数 + 以\(i,j,k,l\)为顶点的正方形个数,\(i,j,k,l\)都代表不同的坏点。
其实说,\(Ans=\) 至少包含\(0\)个坏点的正方形个数 - 至少包含\(1\)个坏点的正方形个数 + 至少包含\(2\)个的个数 - 至少包含\(3\)个的个数 + 至少包含\(4\)个的个数,更好想吧,但注意虽说是正方形个数,同一个位置的正方形是可以被重复统计的。
没有限制的正方形个数,问题在于斜着的正方形有多少个。我们发现每个斜着的正方形都可以被最小的完全包含它的正方形所确定,比如:
这样每个边长为\(i\)的正方形内部都有\(i-1\)个正方形,算上它自己也就是\(i\)个正方形。
所以总的正方形个数就是\(\sum_{i=1}^{\min(n,m)}(n-i+1)*(m-i+1)*i\),可以\(O(n)\)计算。
然后是有\(1\)个坏点作为顶点的正方形个数。同样难在如何计算斜着的正方形。
因为如果一个点在一个正着的正方形的边上,那么就可以唯一确定以这个点为顶点的一个斜着的正方形。如图:
也就是只要它在一个正方形的边上,就可以唯一确定一个斜着的正方形,只需要算这个点在多少个正方形的边上就可以了。
一个点在正方形上边那条边上,和在下边/左边/右边那条边上算起来应该都是差不多的。
所以考虑它在多少个正方形的下边那条边上(朝上的正方形有多少个)。
如图,先不考虑上边界及左右边界限制,有\(i+1\)个长度为\(i\)的正方形的下边包含它。
记\(h,l,r\)分别表示当前点到上/左/右边界的距离,长度的限制就是不超过\(t=\min(l+r,h)\)。那么此时的答案就是\(2+3+4+...+t+1=\frac{t(t+3)}{2}\)。
显然直接这么算出来的正方形是可能超过左右边界的。如图,底下的黑色是边界:
不难看出如果\(t\)超过\(l\),那么超过左边界的正方形有\(1+2+3+...+(t-l)=\frac{(t-l)(t-l+1)}{2}\)个,减掉就可以了。右边界的处理一样。
这样朝上的正方形有多少个就处理完了。朝下/左/右的正方形个数计算同理,把\(h,l,r\)换一下就可以了。
这时我们发现有些正方形会被计算两次,如图中橙色的:
显然这种正方形是完全位于当前点左上方向的,有多少个就算一下到左上边界的距离,减掉就可以了。
这样以至少一个坏点为顶点的正方形就处理完了。复杂度只有\(O(k)\)。
对于以两个坏点为顶点的正方形,显然枚举这两个坏点后就基本确定这个正方形的位置了。
只有以下三种可能且另外两点的坐标可以直接求出:(图来自\(cmd2001\)题解)
黄色的正方形可能顶点直接不在网格上。判一下。
然后求出另外两点,判一下是否越界就可以了。
对于以三/四个坏点为顶点的正方形,在刚刚枚举两个的时候我们已经确定正方形的四个点了,只需要判断确定的这个正方形是否有三/四个坏点就可以了(另外两个点是否也是坏点)。
显然这样对于三个的会重复统计\(C_3^2\)次,对于四个的会重复统计\(C_4^2\)次。除掉就行了。
所以这部分复杂度\(O(k^2\log k)\)或\(O(k^2)\),看你用什么判坏点。
OK,做完啦。
//39924kb 2744ms
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define mod 100000007
#define Legal(x,y) (x>=0&&x<=n&&y>=0&&y<=m)
typedef long long LL;
const int N=2005;
int n,m,t2,t3,t4;
struct Hash_Table
{
#define Sz 10000000
int Enum,H[Sz+2],nxt[N]; LL to[N];
inline void Insert(int x,int y)
{
LL v=1ll*x*1000001+y; x=v%Sz;
to[++Enum]=v, nxt[Enum]=H[x], H[x]=Enum;
}
inline bool Count(int x,int y)
{
LL v=1ll*x*1000001+y;
for(int x=v%Sz,i=H[x]; i; i=nxt[i])
if(to[i]==v) return 1;
return 0;
}
}hs;
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
inline LL Calc(int h,int l,int r)
{
int t=std::min(h,l+r);
if(!t) return 0;
LL res=1ll*t*(t+3);
if(t>l) res-=1ll*(t-l)*(t-l+1);
if(t>r) res-=1ll*(t-r)*(t-r+1);
return (res>>1)%mod;
}
int Calc1(int x,int y)
{
int u=x,d=n-x,l=y,r=m-y;
LL res=(Calc(u,l,r)+Calc(d,l,r)+Calc(l,u,d)+Calc(r,u,d))%mod;
res=res-std::min(u,l)-std::min(u,r)-std::min(d,l)-std::min(d,r);
return (res+mod)%mod;
}
void Calc2(int x1,int y1,int x2,int y2)
{
if(!Legal(x1,y1)||!Legal(x2,y2)) return;
int t=hs.Count(x1,y1)+hs.Count(x2,y2);
++t2;
if(t>=1) ++t3;//if更快啊。。
if(t>=2) ++t3, ++t4;//就算是4个点,以i,j,k为顶点的正方形此时是算两个(i,j固定,k有两个)
// ++t2, t==1?(++t3):(t==2?(t3+=2,++t4):0);
}
int main()
{
static int X[N],Y[N];
n=read(),m=read(); int K=read();
for(int i=1; i<=K; ++i) X[i]=read(),Y[i]=read(),hs.Insert(X[i],Y[i]);
LL ans=0;
for(int i=1,lim=std::min(n,m); i<=lim; ++i) ans+=1ll*(n-i+1)*(m-i+1)%mod*i%mod;
for(int i=1; i<=K; ++i) ans-=Calc1(X[i],Y[i]);
for(int i=1; i<=K; ++i)
{
int x1=X[i],y1=Y[i];
for(int j=i+1; j<=K; ++j)
{
int x2=X[j], y2=Y[j], dx=x1-x2, dy=y1-y2;
Calc2(x1+dy, y1-dx, x2+dy, y2-dx);//边
Calc2(x1-dy, y1+dx, x2-dy, y2+dx);
if((std::abs(dx)+std::abs(dy))&1) continue;
int dx2=dx-dy>>1, dy2=dx+dy>>1;//对角线
Calc2(x1-dx2, y1-dy2, x2+dx2, y2+dy2);
}
}
ans=ans%mod+t2-t3/3+t4/6;
printf("%lld\n",(ans%mod+mod)%mod);
return 0;
}
BZOJ.4558.[JLOI2016]方(计数 容斥)的更多相关文章
- [BZOJ4558]:[JLoi2016]方(容斥+模拟)
题目传送门 题目描述 上帝说,不要圆,要方,于是便有了这道题.由于我们应该方,而且最好能够尽量方,所以上帝派我们来找正方形上帝把我们派到了一个有N行M列的方格图上,图上一共有$(N+1)\times ...
- ●BZOJ 4559 [JLoi2016]成绩比较(容斥)
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4559 题解: 容斥,拉格朗日插值法. 结合网上的另一种方法,以及插值法,可以把本题做到 O( ...
- 【BZOJ 4558】 4558: [JLoi2016]方 (计数、容斥原理)
未经博主同意不能转载 4558: [JLoi2016]方 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 362 Solved: 162 Descri ...
- bzoj 2839 集合计数 容斥\广义容斥
LINK:集合计数 容斥简单题 却引出我对广义容斥的深思. 一直以来我都不理解广义容斥是为什么 在什么情况下使用. 给一张图: 这张图想要表达的意思就是这道题目的意思 而求的东西也和题目一致. 特点: ...
- 4558: [JLoi2016]方
4558: [JLoi2016]方 https://lydsy.com/JudgeOnline/problem.php?id=4558 分析: 容斥原理+各种神奇的计数. 如果没有被删除了的点的话,直 ...
- BZOJ.5407.girls/CF985G. Team Players(三元环计数+容斥)
题面 传送门(bzoj) 传送门(CF) \(llx\)身边妹子成群,这天他需要从\(n\)个妹子中挑出\(3\)个出去浪,但是妹子之间会有冲突,表现为\(i,j\)之间连有一条边\((i,j)\), ...
- 【BZOJ 4455】 [Zjoi2016]小星星 容斥计数
dalao教导我们,看到计数想容斥……卡常策略:枚举顺序.除去无效状态.(树结构) #include <cstdio> #include <cstring> #include ...
- 【BZOJ】4558: [JLoi2016]方
[题意]给定有(n+1)*(m+1)个点的网格图,其中指定k个点不合法,求合法的正方形个数(四顶点合法). [算法]计数 [题解]斜着的正方形很麻烦,所以考虑每个斜正方形其外一定有正的外接正方形. 也 ...
- BZOJ 3294: [Cqoi2011]放棋子 计数 + 容斥 + 组合
比较头疼的计数题. 我们发现,放置一个棋子会使得该棋子所在的1个行和1个列都只能放同种棋子. 定义状态 $f_{i,j,k}$ 表示目前已使用了 $i$ 个行,$j$ 个列,并放置了前 $k$ 种棋子 ...
随机推荐
- Spring声明式事务@Transactional 详解,事务隔离级别和传播行为
@Transactional注解支持9个属性的设置,这里只讲解其中使用较多的三个属性:readOnly.propagation.isolation.其中propagation属性用来枚举事务的传播行为 ...
- 配置web pack loader 报错:Module build failed: Error: The node API for `babel` has been moved to `babel-core`.
报错如下 Module build failed: Error: The node API for `babel` has been moved to `babel-core`. 在我配置loader ...
- pycaffe简明文档
pycaffe简明文档 by ChrisZZ, imzhuo@foxmail.com 2018年01月18日19:00:56 说明 caffe的python接口没有官方说明文档,例如查看一个函数的用法 ...
- JAVA 数据类型数组
普通int: public class Array { //成员变量 private int[] data; private int size; //构造函数,传入数组的容量capacity构造Arr ...
- Java 骚操作--生成二维码
https://www.cnblogs.com/lsy131479/p/8808172.html
- webpack学习笔记--整体配置结构
之前的章节分别讲述了每个配置项的具体含义,但没有描述它们所处的位置和数据结构,下面通过一份代码来描述清楚: const path = require('path'); module.exports = ...
- Java连接MySQL数据库三种方法
好久没有更新博客了!今天利用周目时学习了一下数据库mysql.介绍一下数据库的三种连接方式! 开发工具:Myeclipse MySQL5.6 MySQL连接驱动:mysql-connector-jav ...
- [转] node.js下mongoose简单操作实例
Mongoose API : http://mongoosejs.com/docs/api.html // mongoose 链接 var mongoose = require('mongoose') ...
- 无法创建链接服务器 "ORCL" 的 OLE DB 访问接口 "OraOLEDB.Oracle" 的实例 (错误:7302)
原文:https://www.cnblogs.com/tiger2soft/p/6954308.html 在sqlserver中创建oracle的链接服务器时,提示此错误. 按照网上的方案,先后使用了 ...
- 秒懂C#通过Emit动态生成代码
首先需要声明一个程序集名称, 1 // specify a new assembly name 2 var assemblyName = new AssemblyName("Kitty&qu ...