JLOI/SHOI2016方



SOL:

\(f_i\)表示至少含\(i\)个点的正方形

运用容斥\(ans=f_0-f_1+f_2-f_3+f_4\)

\(f_0\)每个正方形可以转为边长个\(\sum i*(n-i+1)*(m-i+1)\)

\(f_1\)分四块,每块算穿插其中的

我们先看上方那块,向左\(l\),向右\(r\),向上\(u\)

每个扭曲的正方形可以恰好旋成一个正的正方形

\(t=min(l+r,u),ans=\frac{t(t+3))}2-\frac{(t-l)(t-l+1)}2-\frac{(t-r)(t-r+1)}2\)

剩下的直接枚举两点算就好

用手写\(hash\)判点更快

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return f==1?x:-x;
}
#define ll long long
#define re register
const int mod=1e8+7,N=2004,M=1e6+4;
int n,m,k;
const int mo=570707;
struct hashash{
	struct node{
		int x,y,nxt;
	}a[N];
	int first[mo],cnt=0;
    inline void insert(int x,int y){
    	int r=((ll)x*M+y)%mo;
    	for(int i=first[r];i;i=a[i].nxt)
    		if(a[i].x==x&&a[i].y==y)return;
    	a[++cnt].x=x;a[cnt].y=y;
    	a[cnt].nxt=first[r];first[r]=cnt;
	}
	inline bool ask(int x,int y){
		int r=((ll)x*M+y)%mo;
		for(int i=first[r];i;i=a[i].nxt)
			if(a[i].x==x&&a[i].y==y)return 1;
		return 0;
	}
}mp;
struct poin{
	int x,y;
	inline void swp(){
		swap(x,y);
		y=-y;
	}
	inline poin operator -(const poin &a)const{
		return (poin){x-a.x,y-a.y};
	}
	inline poin operator +(const poin &a)const{
		return (poin){x+a.x,y+a.y};
	}
	inline poin operator /(const int &a)const{
		return (poin){x/a,y/a};
	}
	inline bool even(){
		return (x&1)^(y&1);
	}
	inline bool check(){
		return x>=0&&y>=0&&x<=n&&y<=m;
	}
	inline bool ispoin(){
		return check()&&mp.ask(x,y);
	}
}a[N];
inline int f0(){
	int ret=0;
	for(re int i=1,mx=min(n,m);i<=mx;i++)
		ret=((ll)i*(n-i+1)*(m-i+1)+ret)%mod;
	return ret;
}
inline int f1(){
	int ret=0;
	for(re int i=1,l,r,u,d,t;i<=k;i++){
		l=a[i].y;r=m-l;
		u=a[i].x;d=n-u;
		t=min(l+r,u);ret=((ll)t*(t+3)/2-(t>l?(ll)(t-l)*(t-l+1)/2:0)-(t>r?(ll)(t-r)*(t-r+1)/2:0)+ret)%mod;
		t=min(l+r,d);ret=((ll)t*(t+3)/2-(t>l?(ll)(t-l)*(t-l+1)/2:0)-(t>r?(ll)(t-r)*(t-r+1)/2:0)+ret)%mod;
		t=min(l,u+d);ret=((ll)t*(t+3)/2-(t>u?(ll)(t-u)*(t-u+1)/2:0)-(t>d?(ll)(t-d)*(t-d+1)/2:0)+ret)%mod;
		t=min(r,u+d);ret=((ll)t*(t+3)/2-(t>u?(ll)(t-u)*(t-u+1)/2:0)-(t>d?(ll)(t-d)*(t-d+1)/2:0)+ret)%mod;
		ret=(ret-min(l,u)-min(u,r)-min(r,d)-min(d,l))%mod;
	}
	return ret;
}
inline int f2(){
	int ret2=0,ret3=0,ret4=0;
	poin p1,p2,p3,p4;
	for(re int i=1,fl;i<=k;i++)
		for(re int j=1;j<i;j++){
			if(!(a[i].even()^a[j].even())){
				p1=a[i]+a[j];
				p2=a[i]-a[j];p2.swp();
				p3=(p1+p2)/2;
				p4=(p1-p2)/2; 
				if(p3.check()&&p4.check()){
					ret2++;fl=0;
					if(p3.ispoin())ret3++,fl++;
					if(p4.ispoin())ret3++,fl++;
					if(fl==2)ret4++;
				}
			}
			p1=a[j]-a[i];p1.swp();
			p2=a[i]+p1;
			p3=a[j]+p1;
			if(p2.check()&&p3.check()){
				ret2++;fl=0;
				if(p2.ispoin())ret3++,fl++;
				if(p3.ispoin())ret3++,fl++;
				if(fl==2)ret4++;
			}
			p2=a[i]-p1;
			p3=a[j]-p1;
			if(p2.check()&&p3.check()){
				ret2++;fl=0;
				if(p2.ispoin())ret3++,fl++;
				if(p3.ispoin())ret3++,fl++;
				if(fl==2)ret4++;
			}
		}
	return ret2-ret3/3+ret4/6;
}
int main(){
	n=read();m=read();k=read();
	for(re int i=1,x,y;i<=k;i++){
		a[i].x=x=read();a[i].y=y=read();
		mp.insert(x,y);
	}
	cout<<((f0()-f1()+f2())%mod+mod)%mod;
	return (0-0);
}
posted @ 2020-03-21 15:41  starusc  阅读(156)  评论(0)    收藏  举报