问题: 方

时间限制: 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. JVM内核-原理、诊断与优化学习笔记(九):锁

    文章目录 线程安全 多线程网站统计访问人数 多线程访问ArrayList 对象头Mark Mark Word,对象头的标记,32位 描述对象的hash.锁信息,垃圾回收标记,年龄 偏向锁 轻量级锁 B ...

  2. java程序——CPU过高100%及内存泄露排查

    CPU过高 这类问题可以使用 top 命令观察一些,CPU 是不是都被 Java 程序占用了.比如下面这个截图: 服务器的 CPU 大多都被 Java 占用了.这正是我们之前生产上 CPU 过高的一个 ...

  3. 使用python和tushare股票交易日历数据,判断节假日周末休市

    接口:trade_cal 描述:获取各大交易所交易日历数据,默认提取的是上交所 注:tushare模块下载和安装教程,请查阅我之前的文章 输入参数 名称       |       类型        ...

  4. ES6 学习 -- 解构赋值

    一.数组解构 **数组解构,解构出来的值跟数组下标是一一对应的,如果左边变量多于右边数组,则左边后面部分变量值为undefined,如果右边数组元素个数多于左边解构变量个数,则左边变量全都有值,且一一 ...

  5. windows域控导出hash

    #mimikaz导入域内所有hash mimikatz.exe privilege::debug "lsadump::dcsync /domain:test.local /all /csv ...

  6. shell 脚本 功能性语句 read,expr,test

    1. read 从终端输入数据赋值给变量 read val 把读入的数据存放到val中 #!/bin/bash echo -n "please input two number :" ...

  7. 【学术篇】SDOI2008 沙拉公主的困惑

    传送门! 题目在这里... 题目大意? 难道不是说的很清楚了么OvO 求n!中与m!互质的数的个数.. 题目分析. 显然的数论... 所以就是化式子呗.. 一个很显然的性质就是如果\(gcd(a,b) ...

  8. The linux command 之 扩展

    echo * " * "字符意味着匹配文件名中的任意字符,shell会在执行echo命令之前把*扩展成其他内容. 一.路径扩展(pathname Expansion) 通过使用通配 ...

  9. pom parent 标签

    <!--parent用于引用父工程 1.统一管理jar包的版本,其依赖需要在子工程中定义才有效(比如此例) 2.统一的依赖管理(父工程的<dependencies>,子工程不必重新引 ...

  10. day24 模块

     Python之路,Day12 = Python基础12 模块 本质为py程序 分类: 内置模块 time time.time() ---> 当前时间的时间戳:浮点型 time.localtim ...