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$ 种棋子 ...
随机推荐
- tinymce-vue富文本编辑器(翻译)
官方Tinymce Vue组件 翻译来自:https://github.com/tinymce/tinymce-vue 官方文档:https://www.tiny.cloud/docs/general ...
- CentOS6.8安装MySQL5.7.20时报Curses library not found解决
报错如下: CMakeErroratcmake/readline.cmake:83(MESSAGE): Curseslibrarynotfound.Pleaseinstallappropriatepa ...
- linux下的抓包
1. 查看网卡名字 cat /proc/net/dev 2.抓取外网进来的包 tcpdump -i eth0 port -s -w .pcap 3.抓取自己服务器上的两个程序之间访问的数据 换成 lo ...
- python压缩文件
#coding=utf-8 #压缩文件 import os,os.path import zipfile #压缩:传路径,文件名 def zip_compression(dirname,zipfile ...
- 微信录音文件上传到服务器以及amr转化成MP3格式,linux上转换简单方法
微信公众号音频接口开发 根据业务需求,我们可能需要将微信录音保存到服务器,而通过微信上传语音接口上传到微信服务器的语音文件的有效期只有3天,所以需要将文件下载到我们自己的服务器. 上传语音接口 wx. ...
- netty 学习(1)
Netty使用:通过BootStrap来启动.而BootStrap主要分为两类:1.面向连接(TCP)的(ClientBootStrap和ServerBootStrap);2. 非面向连接(UDP)的 ...
- P0505
算法训练 P0505 时间限制:1.0s 内存限制:256.0MB 一个整数n的阶乘可以写成n!,它表示从1到n这n个整数的乘积.阶乘的增长速度非常快,例如,13!就已经比较大了 ...
- 实现用VB.Net/(C#)开发K/3 BOS 插件的真正可行方法
转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用的爽呀,这篇文章写与2011年,看来我以前没有认真去找这个方法呀. https://blog.csdn.net/chzjxgd/arti ...
- 统计各个数据库的各个数据表的总数,然后写入到excel中
1.最近项目基本进入最后阶段了,然后会统计一下各个数据库的各个数据表的数据量,开始使用的报表工具,report-designer,开源的,研究了两天,发现并不是很好使,最后自己下班回去,晚上思考,想着 ...
- CentOS6安装Zabbix4.0
安装依赖包yum install net-snmp-devel libevent-devel libxml2-devel curl-devel libjpeg-devel libpng-devel l ...