问题: 方

时间限制: 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. 使用Devstack部署neutron网络节点

    本文为minxihou的翻译文章,转载请注明出处Bob Hou: http://blog.csdn.net/minxihou JmilkFan:minxihou的技术博文方向是 算法&Open ...

  2. Codeforces 1174B Ehab Is an Odd Person

    题目链接:http://codeforces.com/problemset/problem/1174/B 题意:给定长度 n 的数组,任意俩个相加为奇数的数可以交换数组中的位置,让这个数组尽量从小到大 ...

  3. 案例 查询QC(query_cache)

    案例: 数据库版本 5.7.23 16c 64g 按月分区表,做压力测试 开启QC之前: select * from a where aa=xxx; QPS:每秒处理查询的数量 3000+ 开启之后 ...

  4. HDU 2874 /// tarjan离线求森林里两点的距离

    题目大意: 在一个森林里 询问 u v 两点 若不能到达输出 "Not connected" 否则输出两点距离 https://blog.csdn.net/keyboarderqq ...

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

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

  6. pop&dismiss

    //dismiss到根视图 - (void)dismissToRootViewController{ UIViewController *vc = self; while (vc.presenting ...

  7. boost 条件变量

    // boost 条件变量 // 做个简单的笔记 #include <boost/thread/mutex.hpp> #include <boost/thread/condition ...

  8. PHP算法之盛最多水的容器

    给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) .在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0).找出其中的两条线, ...

  9. RAksmart服务器具备哪些特点?

    美国RAKsmart机房运营多年,前身是提供美国军用服务器业务,拥有着庞大的用户群体和消费者,那RAksmart服务器具备哪些特点呢? 1.美国raksmart服务器特点——硬盘超大 美国raksma ...

  10. Java怎样获取字符串最后出现的位置

    lastIndexOf();表示获取字符串最后出现的位置,倒数的位置 @Test /** * lastIndexOf();//获取字符串最后出现的位置,倒数的位置 * */ public void f ...