Bzoj4558 [JLoi2016]方

Time Limit: 20 Sec  Memory Limit: 256 MB
Submit: 382  Solved: 173

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

HINT

Source

 

数学问题 容斥

不考虑坏点限制,枚举正方形的长度即可算出所有正方形的数量。

ans=总数-至少有一个坏点的正方形+至少有两个坏点的正方形-至少有三个坏点的正方形+至少有四个坏点的正方形

枚举两个坏点作为正方形顶点,可以算出另外两个顶点的坐标,用hash可以判断两顶点是不是坏点,从而累计后三部分答案。

至少有一个坏点的正方形怎么求?

假设这个坏点在一个正方形的边上,枚举正方形的长度,综合考虑四个方向的长度限制,可以计算出方案数。

 

前半个小时看错题,以为求内部没有坏点的正方形方案数,一脸懵X

推错一次式子,又删了代码从头开始写……

各种心累。

  1 /*by SilverN*/
  2 #include<iostream>
  3 #include<algorithm>
  4 #include<cstdio>
  5 #include<cmath>
  6 #include<cstring>
  7 #define LL long long
  8 using namespace std;
  9 const int mod=1e8+7;
 10 const int mxn=10010;
 11 int read(){
 12     int x=0,f=1;char ch=getchar();
 13     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 14     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
 15     return x*f;
 16 }
 17 const int hsmod=100007;
 18 struct hs_eg{LL z;int nxt;}e[mxn<<1];
 19 int hd[hsmod+2],Hct=0;
 20 void hs_insert(LL x){
 21     int u=x%hsmod;
 22     for(int i=hd[u];i;i=e[i].nxt){if(e[i].z==x)return;}
 23     e[++Hct].z=x;e[Hct].nxt=hd[u];hd[u]=Hct;return;
 24     return;
 25 }
 26 int hs_find(LL x){
 27     int u=x%hsmod;
 28     for(int i=hd[u];i;i=e[i].nxt)if(e[i].z==x)return 1;
 29     return 0;
 30 }
 31 //
 32 int n,m,K;
 33 int x[mxn],y[mxn];
 34 LL ans;
 35 int Calc(int lenU,int lenD,int lenR){
 36     LL res=-min(lenU,lenR);
 37     res=res+min(lenR,lenU+lenD);
 38     int r1=lenU,r2=lenD,r3=lenR;
 39     if(r1>r2)swap(r1,r2);
 40     if(r3<=r1)return ((LL)res+r3*(LL)(r3+1)/2)%mod;
 41     res=((LL)res+r1*(LL)(r1+1)/2)%mod;
 42     if(r3<=r2)return ((LL)res+r1*(LL)(r3-r1)%mod)%mod;
 43     res=((LL)res+r1*(LL)(r2-r1)%mod)%mod;
 44     if(r3<=r1+r2) return (res+(LL)(r3-r2)*r1-(LL)(r3-r2)*(r3-r2+1)/2)%mod;
 45     res=(res+(LL)r1*(r1-1)/2)%mod;
 46     return res;
 47 }
 48 //
 49 int res2=0,res3=0,res4=0;
 50 inline bool check(int x,int y){
 51     return (x>=0 && x<=n && y>=0 && y<=m);
 52 }
 53 void UPD(int x1,int y1,int x2,int y2){
 54     if(check(x1,y1) && check(x2,y2)){
 55         bool flag1=0,flag2=0;
 56         res2++;
 57         if(hs_find((LL)x1*(m+1)+y1))flag1=1;//,printf("(%d %d %lld)\n",x1,y1,(LL)x1*m+y1);
 58         if(hs_find((LL)x2*(m+1)+y2))flag2=1;//,printf("(%d %d %lld)\n",x2,y2,(LL)x2*m+y2);
 59         if(flag1)res3++;if(flag2)res3++;
 60         if(flag1 & flag2)res4++;
 61     }
 62     return;
 63 }
 64 int main(){
 65     freopen("in.txt","r",stdin);
 66     int i,j;
 67     n=read();m=read();K=read();
 68     for(i=1;i<=K;i++){
 69         x[i]=read();y[i]=read();
 70         hs_insert((LL)x[i]*(m+1)+y[i]);
 71     }
 72     int ed=min(n,m);
 73     for(i=1;i<=ed;i++)ans=((LL)ans+i*(LL)(n-i+1)%mod*(m-i+1))%mod;//total
 74     //
 75     LL res=0;
 76     //Calc1
 77     for(i=1;i<=K;i++){
 78         res=0;
 79         res=res+Calc(x[i],n-x[i],y[i]);
 80         res=(res+Calc(n-x[i],x[i],m-y[i]))%mod;
 81         res=(res+Calc(y[i],m-y[i],n-x[i]))%mod;
 82         res=(res+Calc(m-y[i],y[i],x[i]))%mod;
 83         ans=(ans-res+mod)%mod;
 84     }
 85     //Calc2 3 4
 86     for(i=1;i<K;i++){
 87         for(j=i+1;j<=K;j++){
 88                 int tmpx=x[j]-x[i];
 89                 int tmpy=y[j]-y[i];
 90                 UPD(x[i]+tmpy,y[i]-tmpx,x[j]+tmpy,y[j]-tmpx);
 91                 UPD(x[i]-tmpy,y[i]+tmpx,x[j]-tmpy,y[j]+tmpx);
 92                 if(abs(tmpx+tmpy)&1)continue;
 93                 tmpy=(tmpx+tmpy)>>1;
 94                 tmpx-=tmpy;
 95                 UPD(x[i]+tmpx,y[i]+tmpy,x[j]-tmpx,y[j]-tmpy);
 96         }
 97     }//
 98 //    printf("ans:%lld\n",ans);
 99 //    printf("%d %d %d\n",res2,res3/3,res4/6);
100     ans=(((LL)ans+res2-res3/3+res4/6)%mod+mod)%mod;
101     printf("%lld\n",ans);
102     return 0;
103 }

 

posted @ 2017-06-01 21:17  SilverNebula  阅读(157)  评论(0编辑  收藏  举报
AmazingCounters.com