码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj4558【JLOI2016】方

时间:2016-06-23 01:07:55      阅读:209      评论:0      收藏:0      [点我收藏+]

标签:

4558: [JLoi2016]方

Time Limit: 20 Sec  Memory Limit: 256 MB
Submit: 185  Solved: 78
[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

Sample Output

1



容斥题没有一道会做的,心累QAQ

也不方 也不圆

我的形状和你擦肩

各自磨损残缺

搬运题解,懒人不解释:http://blog.csdn.net/lych_cys/article/details/51480823




#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define pa pair<int,int>
#define N 2005
#define M 233333
#define mod 100000007
using namespace std;
int n,m,k,ans,c1,c2,c3,c4;
int x[N],y[N];
struct hash
{
	int cnt,head[M+5],a[N],b[N],nxt[N];
	void add(int x,int y)
	{
		int num=(x*233+y)%M;
		a[++cnt]=x;b[cnt]=y;nxt[cnt]=head[num];head[num]=cnt;
	}
	int find(int x,int y)
	{
		int num=(x*233+y)%M;
		for(int i=head[num];i;i=nxt[i]) if (a[i]==x&&b[i]==y) return 1;
		return 0;
	}
}h;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
void calc(int x,int y,int z)
{
	if (!x||!y||z<2) return;
	z=min(z,x+y);x=min(x,z-1);y=min(y,z-1);
	c1=((ll)(z-y)*y%mod+(ll)(z-x+y-1)*(y-z+x)/2%mod+c1)%mod;
}
void check(int x1,int y1,int x2,int y2)
{
	if (x1<0||x1>n||y1<0||y1>m||x2<0||x2>n||y2<0||y2>m) return;
	int tmp=h.find(x1,y1)+h.find(x2,y2);
	c2++;c3+=tmp;if (tmp==2) c4++;
}
void solve(int x1,int y1,int x2,int y2)
{
	check(x1-(y2-y1),y1+x2-x1,x2-(y2-y1),y2+x2-x1);
	check(x1-(y1-y2),y1+x1-x2,x2-(y1-y2),y2+x1-x2);
	if ((x1+x2+y1+y2)%2) return;
	check((x1+x2-y1+y2)/2,(y1+y2+x1-x2)/2,(x1+x2+y1-y2)/2,(y1+y2-x1+x2)/2);
}
int main()
{
	n=read();m=read();k=read();
	F(i,1,k){x[i]=read();y[i]=read();h.add(x[i],y[i]);}
	F(i,1,min(n,m)) ans=((ll)i*(n-i+1)%mod*(m-i+1)%mod+ans)%mod;
	F(i,1,k)
	{
		c1=(c1+min(x[i],y[i])+min(x[i],m-y[i])+min(n-x[i],y[i])+min(n-x[i],m-y[i]))%mod;
		calc(x[i],n-x[i],y[i]);calc(x[i],n-x[i],m-y[i]);
		calc(y[i],m-y[i],x[i]);calc(y[i],m-y[i],n-x[i]);
	}
	F(i,1,k-1) F(j,i+1,k) solve(x[i],y[i],x[j],y[j]);
	ans=((ans-c1+c2-c3/3+c4/6)%mod+mod)%mod;
	printf("%d\n",ans);
	return 0;
}


bzoj4558【JLOI2016】方

标签:

原文地址:http://blog.csdn.net/aarongzk/article/details/51738142

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!