问题: 方

时间限制: 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. hexo next主题深度优化(十一),next主题中加入scrollReveal.js,让文章随着鼠标的滚动,出现点小动作。

    文章目录 效果 scrollReveal简单介绍以及简单操作 参考文档: next主题中加入scrollReveal 给article标签添加属性 给底部的不蒜子添加属性 本地引入依赖并且编写启动函数 ...

  2. 7.springboot+mybatis+redis整合

    选择生成的依赖 选择保存的工程路径 查询已经生成的依赖,并修改mysql的版本 <dependencies> <dependency> <groupId>org.s ...

  3. centos安装与配置R语言

    Linux下安装R语言 一.编译安装 由于采用编译安装,所以需要用到gcc编译环境,在编译前check文件时还会用到libXt-devel和readline-devel两个依赖,所以在编译R语言源码时 ...

  4. Java oop第08章_JDBC01(入门)

    一. JDBC的概念: JDBC(Java Database Connectivity)java数据库链接,是SUN公司为了方便我们Java程序员使用Java程序操作各种数据库管理系统制定的一套标准( ...

  5. shell 脚本 变量使用,取消一个变量,echo

    1. 用户自定义变量,直接使用,赋值的时候等号两边不能有空格 A=100 echo "\$A = $A" # $是取变量A 中的值 "" 号中 \$ 是转译,此 ...

  6. SQL 顺序

    查询语句中select from where group by having order by的执行顺序 查询语句中select from where group by having order by ...

  7. 初识 HTML

    HTML 1.描述 HTML超文本标记语言(英语:HyperText Markup Language)是一种用于创建网页的标准标记语言 您可以使用 HTML 来建立自己的 WEB 站点,HTML 运行 ...

  8. BZOJ 2660 (BJOI 2012) 最多的方案

    Description 第二关和很出名的斐波那契数列有关,地球上的OIer都知道:F1=1, F2=2, Fi = Fi-1 + Fi-2,每一项都可以称为斐波那契数.现在给一个正整数N,它可以写成一 ...

  9. Taro框架---左滑动删除

    index.js import Taro, { Component } from '@tarojs/taro' import { View,ScrollView } from '@tarojs/com ...

  10. exit与return的区别

    ===========================PHP的解释=========================================================== return ...