4558: [JLoi2016]方
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 352 Solved: 156
[ Submit][ Status][ Discuss]
Description
上帝说,不要圆,要方,于是便有了这道题。由于我们应该方,而且最好能够尽量方,所以上帝派我们来找正方形
上帝把我们派到了一个有N行M列的方格图上,图上一共有(N+1)×(M+1)个格点,我们需要做的就是找出这些格点形
成了多少个正方形(换句话说,正方形的四个顶点都是格点)。但是这个问题对于我们来说太难了,因为点数太多
了,所以上帝删掉了这(N+1)×(M+1)中的K个点。既然点变少了,问题也就变简单了,那么这个时候这些格点组成
了多少个正方形呢?
Input
第一行三个整数 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且不
会出现重复的格点。
Output
仅一行一个正整数, 代表正方形个数对 100000007( 10^8 + 7) 取模之后的值
Sample Input
2 2 4
1 0
1 2
0 1
2 1
1 0
1 2
0 1
2 1
Sample Output
1
HINT
Source
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#include<cmath>
#include<stack>
#include<map>
using namespace std;
const int maxn = 2020;
typedef long long LL;
const LL mo = 100000007;
struct Point{
int x,y; Point(){}
Point(int x,int y): x(x),y(y){}
bool operator < (const Point &B) const
{
if (x < B.x) return 1;
if (x > B.x) return 0;
return y < B.y;
}
Point operator - (const Point &B) const {return Point(x - B.x,y - B.y);}
Point operator + (const Point &B) const {return Point(x + B.x,y + B.y);}
}p[maxn];
typedef Point Vector;
int n,m,k,Ans,s1,s2,s3,s4;
map <Point,bool> M;
inline int Mul(const LL &x,const LL &y) {return x * y % mo;}
inline int min(const int &x,const int &y) {return x < y ? x : y;}
inline int Add(const int &x,const int &y) {return x + y < mo ? x + y : x + y - mo;}
inline int Dec(const int &x,const int &y) {return x - y >= 0 ? x - y : x - y + mo;}
void Check(Point p1,Point p2)
{
if (p1.x < 0 || p1.x > n || p1.y < 0 || p1.y > m) return;
if (p2.x < 0 || p2.x > n || p2.y < 0 || p2.y > m) return;
int cnt = 0; ++s2;
if (M.count(p1)) ++cnt; if (M.count(p2)) ++cnt;
if (cnt == 1) ++s3; else if (cnt == 2) ++s4;
}
inline int Calc1(int pos,int res,int N)
{
int ret = 0,now = min(pos,min(res,N - pos));
ret = 1LL * now * (now - 1) / 2LL % mo;
if (now == res) return ret;
int a = pos,b = N - pos; if (a > b) swap(a,b);
b = min(b,res); ret = Add(ret,Mul(b - a,a));
if (b == res) return ret; a = min(res,N);
now = N - (b + 1) + 1; a = a - b;
int g = 1LL * (now + now - a + 1) * a / 2LL % mo;
return Add(ret,g);
}
inline int Calc2(int pos,int res,int N)
{
int ret = 0,now = min(pos,min(res,N - pos));
ret = 1LL * now * (now + 3) / 2LL % mo;
if (now == res) return ret;
int a = pos,b = N - pos; if (a > b) swap(a,b);
b = min(b,res); ret = Add(ret,Mul(b - a,a + 1));
if (b == res) return ret; a = min(res,N);
now = N - (b + 1) + 1; a = a - b;
int g = 1LL * (now + now - a + 1) * a / 2LL % mo;
return Add(ret,g);
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
cin >> n >> m >> k;
for (int i = 1; i <= min(n,m); i++)
Ans = Add(Ans,Mul(Mul(n - i + 1,m - i + 1),i));
for (int i = 1; i <= k; i++)
{
int x,y; scanf("%d%d",&x,&y);
s1 = Add(s1,Calc1(x,y,n));
s1 = Add(s1,Calc1(x,m - y,n));
s1 = Add(s1,Calc2(y,x,m));
s1 = Add(s1,Calc2(y,n - x,m));
p[i] = Point(x,y); M[Point(x,y)] = 1;
}
for (int i = 1; i < k; i++)
for (int j = i + 1; j <= k; j++)
{
Vector v = p[j] - p[i]; swap(v.x,v.y);
v.y *= -1; Check(p[i] + v,p[j] + v);
v.x *= -1; v.y *= -1; Check(p[i] + v,p[j] + v);
v = p[j] - p[i]; if ((v.x + v.y) & 1) continue;
Vector g = Point((v.x + v.y) / 2,(v.y - v.x) / 2);
Vector h = Point((v.x - v.y) / 2,(v.y + v.x) / 2);
Check(p[i] + g,p[i] + h);
}
s3 /= 3; s4 /= 6; s3 += s4 * 4;
cout << ((Ans - s1 + s2 - s3 + s4) % mo + mo) % mo << endl;
return 0;
}