【题意】给定有(n+1)*(m+1)个点的网格图,其中指定k个点不合法,求合法的正方形个数(四顶点合法)。
【算法】计数
【题解】斜着的正方形很麻烦,所以考虑每个斜正方形其外一定有正的外接正方形。
也就是,一个边长为x的正放的正方形,同时代表x个正方形(其中1~x-1为斜正方形)。
num0:首先计算所有点合法时全图的正方形个数。
枚举长度i,则num0=∑i*(n-i+1)*(m-i+1)。(长度为i的情况下,左上角多大的矩形能作为左上端点)
num1:减去单个不合法点构成的正方形
对于一个不合法点有四个方向,任意一个方向可以视为calc(l,r,h),l为向左延伸长度,r为向右,h为向上。
包含斜放的正方形在内,也就是一条线段只要接触到该点就会有一个该点构成的正方形。
考虑长度为1的情况是(0,1)(1,0),长度为2是(0,2)(1,1)(2,0),随长度递增答案有以下规律,只要判断h在哪个区间就可以快速计算答案:
当长度为0,答案为0。
当长度为1~min(l,r),数列递增,答案为(h+3)*h/2。
当长度为min(l,r)+1~max(l,r),数列为常数min(l,r)+1,答案为(min+3)*min/2+(h-min)*(min+1)。(一边受限)
当长度为max(l,r)+1~min(l,r)+max(l,r),数列递减,答案为(min+3)*min/2+(max-min)*(min+1)+(min*2+1-h+max)*(h-max)/2。(两边受限)
当长度为min+max+1~+∞,答案为(min+3)*min/2+(max-min)*(min+1)+(min+1)*min/2
细心推一推就可以了。
num2:加上两个不合法点构成的正方形
枚举两个不合法点(A,B)(C,D)的连边,有两种情况:
作为边:另外两个点是(A+D-B,B+A-C)(C+D-B,D+A-C),或另一方向的(A+B-D,B+C-A)(C+B-D,D+C-A)。
作为对角线,利用全等三角形解方程可得,另外两个点是((A-D+B+C)/2,B+C-(A-D+B+C)/2)((A-B+D+C)/2,A+D-(A-B+D+C)/2)。
判断另外两个点是否整点和是否在界内。
num3:减去三个不合法点构成的正方形
在枚举计算num2的时候可以顺便求得(二分另外两个点判断是否是不合法点),当然这样每三个点会被计算3次,除以三即可。
注意,每三个点构成了一个正方形时都应该统计一次,这样粗糙的统计才是容斥的基础。(手算一下就可以得知了)
num4:加上四个不合法点构成的正方形
计算num2时顺便求得,这样每四个点会被计算6次,除以6即可。
综上所述,ans=num0-num1+num2-num3+num4。
注意一些细节,如fabs(x-(int)(x+eps))<=eps。
#include
#include
#include
#include
#include
#include
#include<set>
#include
#include
View Code