题意
T
T
T组数据,每组数据给你一个正整数
n
n
n,然后给你笛卡尔坐标系下
n
n
n个矩形的左下角和右上角的点的坐标
(
x
i
1
,
y
i
1
)
,
(
x
i
2
,
y
i
2
)
(x_{i_1},y_{i_1}),(x_{i_2},y_{i_2})
(xi1,yi1),(xi2,yi2),保证矩形之间不会有重叠,求出所有的对称轴。
输出格式:第一行一个整数
s
z
sz
sz,表示对称轴数量。接下来一行输出若干条对称轴的三个参数,一条对称轴的三个参数形式为
a
a
a
b
b
b
c
c
c,表示对称轴
a
x
+
b
y
=
c
ax+by=c
ax+by=c
(
g
c
d
(
a
,
b
,
c
)
=
1
)
(gcd(a,b,c)=1)
(gcd(a,b,c)=1),相邻两个数以空格隔开,按输出形式的最大字典序输出(对这些对称轴排序,字典序即为参数依次比较大小)。
数据范围:
1
⩽
n
⩽
1
0
5
,
∣
x
∣
,
∣
y
∣
⩽
1
0
9
1\leqslant n\leqslant 10^5,\vert x\vert,\vert y\vert \leqslant 10^9
1⩽n⩽105,∣x∣,∣y∣⩽109
x
i
1
<
x
i
2
,
y
i
1
<
y
i
2
,
∑
n
⩽
1
0
5
x_{i_1}\lt x_{i_2},y_{i_1}\lt y_{i_2},\sum_{}n\leqslant 10^5
xi1<xi2,yi1<yi2,∑n⩽105
思路
在本题中,我们可以获得以下结论:
①结论1:对称轴最多为四条,即两条分别与横纵坐标轴平行的直线和两条斜率分别为1和-1的直线。
其实挺好想的,因为给定的矩形的边都是平行坐标轴的,提示里面也画出来了。
②结论2:设所有矩形的端点中,横纵坐标的最小、最大值分别为
m
n
x
,
m
x
x
,
m
n
y
,
m
x
y
mnx,mxx,mny,mxy
mnx,mxx,mny,mxy,则对称轴若存在,一定存在于以下四条直线中:
设
d
x
=
(
m
n
x
+
m
x
x
)
/
2
,
d
y
=
(
m
x
y
+
m
x
y
)
/
2
dx=(mnx+mxx)/2,dy=(mxy+mxy)/2
dx=(mnx+mxx)/2,dy=(mxy+mxy)/2
x
=
d
x
x=dx
x=dx
y
=
d
y
y=dy
y=dy
x
−
y
=
d
x
−
d
y
x-y=dx-dy
x−y=dx−dy
x
+
y
=
d
x
+
d
y
x+y=dx+dy
x+y=dx+dy
由结论1推导而来。
③结论3:设所有点中,被奇数个矩形覆盖的点为奇点,被偶数个矩形覆盖的点为偶点,那么我们只需要依次判断所有奇点是否满足对称性即可。
因为偶点必定为
180
°
180°
180° 或者
360
°
360°
360° ,奇点必定是
90
°
90°
90° 或者
270
°
270°
270° ,因此奇点必定是转角,而偶点则落在边上。
④当你很容易的得到以上结论以后,就可以用一个
m
a
p
map
map存下所有点被覆盖的次数,然后对每条对称轴,对每个奇点依次进行判断即可。注意字典序最大和输出格式,由于求对称轴有
/
2
/2
/2操作,因此我们先将所有的点的坐标值扩大两倍,化简参数用
g
c
d
gcd
gcd即可(注意保证字典序最大,可能
g
c
d
gcd
gcd要取负),最后对所有坐标轴手写一个比较函数。
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dep(i,a,b) for(int i=(a);i>=(b);i--)
#define VV vector<int>
#define PP pair<ll,ll>
#define ls (rt<<1)
#define rs (rt<<1|1)
#define fi first
#define se second
#define pb push_back
using namespace std;
typedef long long ll;
template <typename T>
inline void read(T &X){
X=0;int w=0; char ch=0;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
if(w) X=-X;
}
const int maxn=4e5+5;
//const double pi=acos(-1.0);
//const double eps=1e-9;
//const ll mo=1e9+7;
int n,m,k;
vector<ll> go(ll x,ll y,ll z){
//cout << "begin: " << x << " " << y << " " << z << endl;
vector<ll> vc(3);
ll d = __gcd(x, __gcd(y, z));
if(x/d<0)
d = -d;
else if(!x&&y/d<0)
d = -d;
vc[0] = x / d;
vc[1] = y / d;
vc[2] = z / d;
//cout << "end: " << x/d<< " " << y/d << " " << z/d << endl;
return vc;
}
bool ok[4];
bool cmp(vector<ll>&a,vector<ll>&b){
if(a[0]!=b[0])
return a[0] > b[0];
if(a[1]!=b[1])
return a[1] > b[1];
return a[2] > b[2];
}
void solve(){
read(n);
map<PP, int> mp;
ll mnx = inf, mxx = -inf, mny = inf, mxy = -inf;
rep(i,1,n){
ll x, y,xx,yy;
read(x);
read(y);
read(xx);
read(yy);
x <<= 1;
y <<= 1;
xx <<= 1;
yy <<= 1;
mp[{x, y}] ^= 1;
mp[{xx, y}] ^= 1;
mp[{x, yy}] ^= 1;
mp[{xx, yy}] ^= 1;
mnx = min(mnx, x);
mny = min(mny, y);
mxx = max(mxx, xx);
mxy = max(mxy, yy);
}
ll dx = (mnx + mxx) / 2, dy = (mny + mxy) / 2;
rep(i, 0, 3) ok[i] = true;
for(auto i:mp){
if(!i.se)
continue;
PP p = {i.fi.fi, i.fi.se};
ll x, y;
x = p.fi, y = dy - (p.se - dy);
ok[0] = (ok[0] && mp.count({x,y}) && mp[{x,y}]);
x = dx - (p.fi - dx), y = p.se;
ok[1] = (ok[1] && mp.count({x,y}) && mp[{x,y}]);
x = dx + (p.se - dy), y = dy + (p.fi - dx);//
ok[2] = (ok[2] && mp.count({x,y}) && mp[{x,y}]);
x = dx - (p.se - dy), y = dy - (p.fi - dx);//
ok[3] = (ok[3] && mp.count({x,y}) && mp[{x,y}]);
}
vector<vector<ll>> ans;
if(ok[0]) ans.push_back(go(0, 2, dy));
if(ok[1]) ans.push_back(go(2, 0, dx));
if(ok[2]) ans.push_back(go(2, -2, dx-dy));
if(ok[3]) ans.push_back(go(2, 2, dx+dy));
int sz = ans.size();
sort(ans.begin(), ans.end(), cmp);
printf("%d\n", sz);
rep(i,0,sz-1){
int k = 0;
for(auto j:ans[i]){
printf("%lld", j);
if(!(i==sz-1&&k==2))
printf(" ");
k++;
}
}
puts("");
}
int main(){
// freopen("e://duipai//amyout.txt","w",stdout);
int T=1,cas=1;
read(T);
while(T--){
solve();
}
//system("pause");
return 0;
}