问题: 方

时间限制: 2 Sec  内存限制: 256 MB

题面


题目描述

上帝说,不要圆,要方,于是便有了这道题。由于我们应该方,而且最好能够尽量方,所以上帝派我们来找正方形 上帝把我们派到了一个有N行M列的方格图上,图上一共有(N+1)×(M+1)个格点,我们需要做的就是找出这些格点形成了多少个正方形(换句话说,正方形的四个顶点都是格点)。但是这个问题对于我们来说太难了,因为点数太多 了,所以上帝删掉了这(N+1)×(M+1)中的K个点。既然点变少了,问题也就变简单了,那么这个时候这些格点组成了多少个正方形呢?

输入格式

第一行三个整数 N, M, K, 代表棋盘的行数、 列数和不能选取的顶点个数。 保证 N, M >= 1, K <=(N + 1) × (M + 1)。约定每行的格点从上到下依次用整数 0 到 N 编号,每列的格点依次用 0到 M 编号。接下来 K 行,每 行两个整数 x,y 代表第 x 行第 y 列的格点被删掉了。保证 0 <=x <=N<=10^6, 0 <=y<=M<=10^6,K<=2*1000且不 会出现重复的格点。

输出格式

仅一行一个正整数, 代表正方形个数对 100000007( 10^8 + 7) 取模之后的值

样例输入

2 2 4

1 0

1 2

0 1

2 1

样例输出

1

题解


此题有毒!卡了我一整天。

从昨天下午一点多开始一直到今天的十一点,我才A掉了这到毒瘤题……

细节超多。

我们直接统计没有坏点的正方形个数显然不现实。暴力……没敢想。最起码$O(n^4)$的吧……

所以需要容斥原理。

我们处理出至少有零个坏点的正方形个数sum0,至少有一个坏点的正方形个数sum1,以此类推sum2、sum3和sum4的含义。

然后考虑怎么处理。

处理sum0:

我们通过观察得出这样的性质:

1.每一个斜正方形必定有唯一确定的包含它的最小的正正方形。

2.每一个边长为x的正正方形中包含着包括它自身共x个正方形。

于是我们推出式子:

$\sum\limits_{i=1}^{min(n,m)}{i*(n-i+1)*(m-i+1)}$

(i枚举边长,$(n-i+1)和(m-i+1)$的意义为平移后的个数。详情参见本人题解:数三角形)

然后就可以在O(n)时间内求出sum0。

处理sum1:

这道题最精髓(毒瘤)的部分。(查了若干份题解才搞明白还有一大堆结论没证……)

依然通过观察和理性思考,我们发现这样一个性质:

如果一个坏点在某一个正正方形的边上或者端点上,

那么它唯一对应这个正正方形中存在的某一个顶点均在正正方形边上的正方形(斜正方形或正正方形本身)

于是我们可以只去考虑该坏点位于正正方形的边上或者点上的情况。

问题转化为:过该坏点的正正方形有多少个。

枚举每一个坏点,我们考虑分情况讨论:该坏点在某个正方形的四个点上或四个边上。

四个顶点好求。由于保证是正正方形,我们只需要保证它不超过边界。

设该正方形距离左边界的距离为l,距右边界距离为r,距上边界距离为u,距下边界距离为d。

于是十分愉快一行取min走起:$sum1+=min(l,u),sum+=min(l,d),sum+=min(r,u),sum+=min(r,d)$;

接下来考虑坏点位于四个边上。

颓了一些性质(自己至今没有证上来……心里发虚)

我们只考虑左边界、右边界和上边界的关系来统计,其他直接旋转推广。

设该坏点距左边界的距离为x,距右边界的距离为y,距上边界的距离为h,

则有:

如果h<=min(x,y),对答案的贡献为h*(h+1)/2%mod;

如果min(x,y)<h<=max(x,y),对答案的贡献为min(x,y)*(min(x,y)+2)+min(x,y)*(h-min(x,y))

如果max(x,y)<h<=x+y,对答案的贡献为

min(x,y)*(min(x,y)+1)/2+min(x,y)*(max(x,y)-min(x,y))+(min(x,y)-1+min(x,y)-h+max(x,y))*(h-max(x,y))/2

如果h>x+y,对答案的贡献为x*y。

推广到四个方向,分别将左右上边界附成(l,r,u)(l,r,d)(u,d,l)(u,d,r)分别计算贡献即可。

处理sum2:

处理$sum2$的时候需要注意,我们处理出来的sum2是至少包含2个坏点的正方形总数。所以无需保证正方形的另外两个点不是坏点(我因为没想透卡了一小会儿)

所以我们只需要枚举两个坏点作为正方形的两个顶点,然后讨论这两个坏点作为正方形的边上的顶点和对角线上的顶点两种情况,讨论另外两个点是否在界内以及是否整点来统计答案。

作为边:1.另外两个点是$(A+D-B,B+A-C)(C+D-B,D+A-C)$

    2.另一方向的$(A+B-D,B+C-A)(C+B-D,D+C-A)$。

作为对角线,(利用全等三角形解方程可得):另外两个点是$((A-D+B+C)/2,B+C-(A-D+B+C)/2)((A-B+D+C)/2,A+D-(A-B+D+C)/2)$。

处理sum3、sum4:

这个显然和sum2放到一起就可以了。

网上的题解基本上一笔带过。然而细节还是需要处理一下的。

首先是判定问题。我最开始打了个暴搜判定,枚举每一个坏点坐标,匹配上了就返回1,否则一直搜到末尾返回0。

T到了2000ms。(真的飞起来了欸!)

然后学题解打hash链表,超快的说。783ms解决问题。

然而我sb的把模数设到了1e8+7,觉得可以借这个题给模数省一个define……

然后他就给了我一堆美妙的re。最开始re30,把数组压到1e7是re40,我意识到事情不太对,赶紧重开模数给它削了俩0,A了……

(好长啊 /仰望,给个推荐呗~)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#define mod 100000007
#define ll long long
#define int long long
#define K 1000007
using namespace std;
int n,m,k;
int sum0,sum1,sum2,sum3,sum4;
struct node{int x,y;}wor[];
struct hsss{int key,nxt;}data[];
int num,h[];
//bool iswor[3003][3003];
inline int query(int x,int y)
{
for(register int i=;i<=k;++i)
if(wor[i].x==x&&wor[i].y==y)
return ;
return ;
}
inline void ins(int key)
{
int x=key%K;
for(int i=h[x];i;i=data[i].nxt)
if(data[i].key==key)return;
data[++num].key=key;data[num].nxt=h[x];h[x]=num;
}
inline int cal(int x,int y,int h)
{
h-=;
if(x>y)swap(x,y);
if(h<=x)return (ll)h*(h+)/%mod;
if(h<=y)return ((ll)x*(x+)/+(ll)x*(h-x))%mod;
if(h>=x+y)return (ll)x*y%mod;
return ((ll)x*(x+)/+(ll)x*(y-x)+(ll)(x-+x-h+y)*(h-y)/)%mod;
}
/*inline bool query(int key)
{
int x=key%K;
for(int i=h[x];i;i=data[i].nxt)
if(data[i].key==key) return 1;
return 0;
}*/
inline void check(int x1,int y1,int x2,int y2)
{
if(x1<||x1>n||x2<||x2>n||y1<||y1>m||y2<||y2>m)return;
int res=query(x1,y1)+query(x2,y2);
sum2+=;if(sum2>=mod)sum2-=mod;
sum3+=res;if(sum3>=mod)sum3-=mod;
sum4+=(res==);if(sum4>=mod)sum4-=mod;
}
signed main()
{
scanf("%lld %lld %lld",&n,&m,&k);
for(register int i=;i<=k;++i){scanf("%lld %lld",&wor[i].x,&wor[i].y);ins(wor[i].x*(m+)+wor[i].y);}
for(register int i=;i<=min(n,m);++i){sum0+=i*(n-i+)*(m-i+)%mod;sum0%=mod;}
for(register int i=;i<=k;++i)
{
int l=wor[i].x,r=n-wor[i].x,u=wor[i].y,d=m-wor[i].y;
sum1+=min(l,u)+min(l,d)+min(r,u)+min(r,d);
if(sum1>=mod)sum1-=mod;
sum1+=cal(l,r,u);if(sum1>=mod)sum1-=mod;
sum1+=cal(l,r,d);if(sum1>=mod)sum1-=mod;
sum1+=cal(u,d,l);if(sum1>=mod)sum1-=mod;
sum1+=cal(u,d,r);if(sum1>=mod)sum1-=mod;
/*
int l=wor[i].x,r=m-wor[i].x,u=wor[i].y,d=n-wor[i].y;
int mn=min(l,r),mx=max(l,r);
if(u<=mn)sum1+=(u+3)*u/2;
else if(u>mn&&u<=mx)sum1+=(mn+3)*mn/2+(u-mn)*(mn+1);
else if(u>=mx+mn+1)sum1+=(mn+3)*mn/2+(mx-mn)*(mn+1)+(mn+1)*mn/2;
else sum1+=(mn+3)*mn/2+(mx-mn)*(mn+1)+(mn*2+1-u+mx)*(u-mx)/2;
if(d<=mn)sum1+=(d+3)*d/2;
else if(d>mn&&d<=mx)sum1+=(mn+3)*mn/2+(d-mn)*(mn+1);
else if(d>=mx+mn+1)sum1+=(mn+3)*mn/2+(mx-mn)*(mn+1)+(mn+1)*mn/2;
else sum1+=(mn+3)*mn/2+(mx-mn)*(mn+1)+(mn*2+1-d+mx)*(d-mx)/2;
mn=min(u,d),mx=max(u,d);
if(l<=mn)sum1+=(l+3)*l/2;
else if(l>mn&&l<=mx)sum1+=(mn+3)*mn/2+(l-mn)*(mn+1);
else if(l>=mx+mn+1)sum1+=(mn+3)*mn/2+(mx-mn)*(mn+1)+(mn+1)*mn/2;
else sum1+=(mn+3)*mn/2+(mx-mn)*(mn+1)+(mn*2+1-l+mx)*(l-mx)/2;
if(r<=mn)sum1+=(r+3)*r/2;
else if(r>mn&&r<=mx)sum1+=(mn+3)*mn/2+(r-mn)*(mn+1);
else if(r>=mx+mn+1)sum1+=(mn+3)*mn/2+(mx-mn)*(mn+1)+(mn+1)*mn/2;
else sum1+=(mn+3)*mn/2+(mx-mn)*(mn+1)+(mn*2+1-r+mx)*(r-mx)/2;
*/
}
for(register int i=;i<k;++i)
{
for(register int j=i+;j<=k;++j)
{
int x1=wor[i].x,y1=wor[i].y,x2=wor[j].x,y2=wor[j].y;
check(x1+y2-y1,y1+x1-x2,x2+y2-y1,y2+x1-x2);
check(x1+y1-y2,y1+x2-x1,x2+y1-y2,y2+x2-x1);
if((x1+x2+y1+y2)&) continue;
check(x1+x2+y2-y1>>,y1+y2+x1-x2>>,x1+x2+y1-y2>>,y1+y2+x2-x1>>);
/*
if(A+D-B>0||B+A-C>0||A+D-B<m||B+A-C<n)
if(C+D-B>0||C+D-B<m||D+A-C>0||D+A-C<n)
{
sum2++;
if(query(A+D-B,B+A-C)||query(C+D-B,D+A-C))sum3++;
if(query(A+D-B,B+A-C)&&query(C+D-B,D+A-C))sum4++;
}
if((A-D+B+C)%2)continue;if((A-D+B+C)%2)continue;
if((A-B+D+C)%2)continue;if((A-B+D+C)%2)continue;
if((A-D+B+C)/2>0&&(A-D+B+C)/2<m&&B+C-(A-D+B+C)/2>0&&B+C-(A-D+B+C)/2<n)
if((A-B+D+C)/2>0&&(A-B+D+C)/2<m&&A+D-(A-B+D+C)/2>0&&A+D-(A-B+D+C)/2<n)
{
sum2++;
if(query((A-D+B+C)/2,B+C-(A-D+B+C)/2)||query((A-B+D+C)/2,A+D-(A-B+D+C)/2))sum3++;
if(query((A-D+B+C)/2,B+C-(A-D+B+C)/2)&&query((A-B+D+C)/2,A+D-(A-B+D+C)/2))sum4++;
}
*/
}
}
// cout<<sum0<<" "<<sum1<<" "<<sum2<<" "<<sum3<<" "<<sum4<<endl;
cout<<((sum0-sum1+sum2-sum3/+sum4/)%mod+mod)%mod<<endl;
return ;
}

ps:注释掉的是我的调试和重构代码前的代码……写崩了……

「题解」:[BZOJ4558]方的更多相关文章

  1. 「题解」「美团 CodeM 资格赛」跳格子

    目录 「题解」「美团 CodeM 资格赛」跳格子 题目描述 考场思路 思路分析及正解代码 「题解」「美团 CodeM 资格赛」跳格子 今天真的考自闭了... \(T1\) 花了 \(2h\) 都没有搞 ...

  2. 「题解」「HNOI2013」切糕

    文章目录 「题解」「HNOI2013」切糕 题目描述 思路分析及代码 题目分析 题解及代码 「题解」「HNOI2013」切糕 题目描述 点这里 思路分析及代码 题目分析 这道题的题目可以说得上是史上最 ...

  3. 「题解」JOIOI 王国

    「题解」JOIOI 王国 题目描述 考场思考 正解 题目描述 点这里 考场思考 因为时间不太够了,直接一上来就着手暴力.但是本人太菜,居然暴力爆 000 ,然后当场自闭- 一气之下,发现对 60pts ...

  4. 「题解」:[loj2763][JOI2013]现代豪宅

    问题 A: 现代豪宅 时间限制: 1 Sec  内存限制: 256 MB 题面 题目描述 (题目译自 $JOI 2013 Final T3$「現代的な屋敷」) 你在某个很大的豪宅里迷路了.这个豪宅由东 ...

  5. 「题解」:07.16NOIP模拟T2:通讯

    问题 B: 通讯 时间限制: 1 Sec  内存限制: 256 MB 题面 题目描述 “这一切都是命运石之门的选择.” 试图研制时间机器的机关SERN截获了中二科学家伦太郎发往过去的一条短 信,并由此 ...

  6. 「题解」:$Six$

    问题 A: Six 时间限制: 1 Sec  内存限制: 512 MB 题面 题面谢绝公开. 题解 来写一篇正经的题解. 每一个数对于答案的贡献与数本身无关,只与它包含了哪几个质因数有关. 所以考虑二 ...

  7. 「题解」:$Smooth$

    问题 A: Smooth 时间限制: 1 Sec  内存限制: 512 MB 题面 题面谢绝公开. 题解 维护一个队列,开15个指针,对应前15个素数. 对于每一次添加数字,暴扫15个指针,将指针对应 ...

  8. 「题解」:Kill

    问题 A: Kill 时间限制: 1 Sec  内存限制: 256 MB 题面 题面谢绝公开. 题解 80%算法 赛时并没有想到正解,而是选择了另一种正确性较对的贪心验证. 对于每一个怪,我们定义它的 ...

  9. 「题解」:y

    问题 B: y 时间限制: 1 Sec  内存限制: 256 MB 题面 题面谢绝公开. 题解 考虑双向搜索. 定义$cal_{i,j,k}$表示当前已经搜索状态中是否存在长度为i,终点为j,搜索过边 ...

随机推荐

  1. 线性可分SVM中线性规划问题的化简

    在网上找了许多关于线性可分SVM化简的过程,但似乎都不是很详细,所以凭借自己的理解去详解了一下. 线性可分SVM的目标是求得一个超平面(其实就是求w和b),在其在对目标样本的划分正确的基础上,使得到该 ...

  2. Python匹马行天下之初识python!

    python的发展史 1989年,被称为龟叔的Guido在为ABC语言写插件时,产生了写一个简洁又实用的编程语言的想法,并开始着手编写.因为其喜欢Monty Python喜剧团,所以将其命名为pyth ...

  3. Round Numbers /// 组合计数 oj21455

    题目大意: 给定a,b 输出[a,b]的闭区间中round number的数量 所谓round就是一个数在二进制下0的个数大于等于1的个数 0的个数>=1的个数 也就是1的个数<=0的个数 ...

  4. Spring MVC @RequestMapping注解详解(2)

    @RequestMapping 参数说明 value:定义处理方法的请求的 URL 地址.(重点) method:定义处理方法的 http method 类型,如 GET.POST 等.(重点) pa ...

  5. Producer-Consumer 生产者,消费者

    这个模式跟Guarded模式有点类似,不过需要一个控制台限制请求方和处理方的频度和数量. public class ProducerConsumerTest { /** * @param args * ...

  6. 安装rubygems

    转载 http://blog.csdn.net/huanghai200911/article/details/51251472 1,下载rubygems-2.4.8.tar包,下载地址:https:/ ...

  7. CTR预估的常用方法

    1.CTR CTR预估是对每次广告的点击情况做出预测,预测用户是点击还是不点击. CTR预估和很多因素相关,比如历史点击率.广告位置.时间.用户等. CTR预估模型就是综合考虑各种因素.特征,在大量历 ...

  8. erlang 开发建议

    * 确保没有任何编译警告 * Erlang中String采用list实现,32位系统中,其1个字符用8个字节的空间(4个保存value, 4个保存指针).因此string速度较慢,空间占用较大 * 在 ...

  9. C/C++ nullptr

    nullptr 关键字表示空指针值. 空指针值可用于指明对象句柄.内部指针或本机指针类型不指向对象. 结合使用 nullptr 与托管代码或本机代码. 编译器为托管空指针值和本机空指针值发出相应但不同 ...

  10. 0916CSP-S模拟测试赛后总结

    40分-rank35. 不想找借口.实力不行. 赛时状态没出什么大问题.就是实力太弱了. 天皇又AK了.去问了一下,他说全是简单题…… 后来发现一些人用非正解AC了. 但是天皇题题正解题题首切啊. 还 ...