• 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)
    ",x1,y1,(LL)x1*m+y1);
     58         if(hs_find((LL)x2*(m+1)+y2))flag2=1;//,printf("(%d %d %lld)
    ",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
    ",ans);
     99 //    printf("%d %d %d
    ",res2,res3/3,res4/6);
    100     ans=(((LL)ans+res2-res3/3+res4/6)%mod+mod)%mod;
    101     printf("%lld
    ",ans);
    102     return 0;
    103 }
  • 相关阅读:
    删除使用RMAN命令备份的文件
    查看.Net Framework版本的方法(zz)
    c# Foreach last (zz)
    Visual Studio 2008 QFE (zz)
    打印机的接口
    牛人的PENTAX单反之路
    我新进的宾得K10D机器和镜头
    买车险要有足额第三者责任险
    谈谈P家的SUPERTAKUAMR
    硬盘接口总结
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/6930805.html
Copyright © 2020-2023  润新知