2019-2020 ICPC香港 A. Axis of Symmetry (思维+结论)

传送门
在这里插入图片描述
在这里插入图片描述

题意

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 1n105,x,y109
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,n105

思路

在本题中,我们可以获得以下结论:
结论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 xy=dxdy
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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值