首先通过容斥转化为求:所有正方形-至少有1个坏点的正方形+至少有2个的-至少有3个的+有4个的。
所有正方形:显然一个正方形不管是斜的还是正的,它所占的网格中的空间一定是一个正的正方形,不妨称为该正方形的框架。于是我们可以枚举这个正方形的框架的边长,然后枚举偏离多少格即可。
至少有1个坏点:我们枚举坏点,然后同样枚举包含这个坏点的正方形的框架,那么这个坏点在框架上的位置,共两个大类(在边上不在角上和在角上),八个小类(四条边四个角)分别统计一下即可。
至少有2个坏点:枚举2个坏点,此时正方形就是固定的共三种形态,算出三种形态的四个角统计即可。可以顺便把含3,4个坏点的一起统计。
最后注意一个正方形可能被多次统计。
AC代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #define ll long long #define mod 100000007 #define gets(x,y) ((ll)((x)+(y))*((y)-(x)+1)>>1) #define N 2005 using namespace std; int m,n,cnt,ans,t1,t2,t3,t4,a[N],b[N]; struct hsh_node{ int tot,fst[2010527],px[N],py[N],nxt[N]; void ins(int x,int y){ int z=(x*97+y)%2010527; px[++tot]=x; py[tot]=y; nxt[tot]=fst[z]; fst[z]=tot; } int find(int x,int y){ int z=(x*97+y)%2010527,p; for (p=fst[z]; p; p=nxt[p]) if (px[p]==x && py[p]==y) return 1; return 0; } }hsh; bool inmp(int x,int y){ return x>=0 && x<=m && y>=0 && y<=n; } 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); t1=(t1+(ll)(z-y)*y)%mod; t1=(t1+gets(z-x,y-1))%mod; } void updt(int u1,int v1,int u2,int v2){ if (inmp(u1,v1) && inmp(u2,v2)){ int tmp=hsh.find(u1,v1)+hsh.find(u2,v2); t2++; t3+=tmp; if (tmp>1) t4++; } } void solve(int x1,int y1,int x2,int y2){ int dx=x2-x1,dy=y2-y1; updt(x1+dy,y1-dx,x2+dy,y2-dx); updt(x1-dy,y1+dx,x2-dy,y2+dx); if (abs(dx+dy)&1) return; dy=(dx+dy)>>1; dx-=dy; updt(x1+dx,y1+dy,x2-dx,y2-dy); } int main(){ scanf("%d%d%d",&m,&n,&cnt); int i,j; for (i=1; i<=cnt; i++){ scanf("%d%d",&a[i],&b[i]); hsh.ins(a[i],b[i]); } for (i=1; i<=m && i<=n; i++) ans=(ans+(ll)i*(m-i+1)%mod*(n-i+1))%mod; for (i=1; i<=cnt; i++){ calc(a[i],m-a[i],b[i]); calc(a[i],m-a[i],n-b[i]); calc(b[i],n-b[i],a[i]); calc(b[i],n-b[i],m-a[i]); t1=(t1+min(a[i],b[i])+min(a[i],n-b[i])+min(m-a[i],b[i])+min(m-a[i],n-b[i]))%mod; for (j=1; j<i; j++) solve(a[i],b[i],a[j],b[j]); } printf("%d\n",(ans-t1+t2-t3/3+t4/6+mod)%mod); return 0; }
by lych
2016.5.23