Codeforces 2072E 题解

题目大意

在一个平面直角坐标系上设置 \(n\) 个点,第 \(i\) 个点的坐标为 \((x_i,y_i)\)。给定 \(k\),求一个恰有 \(k\) 个点对 \((i,j)\),满足这 2 个点的欧几里得距离和曼哈顿距离相等的设点方案。

题目思路

我们先思考在何种情况下会满足题目需要的条件,即 2 个点的欧几里得距离和曼哈顿距离相等。我们在坐标系上先假定 2 个点的位置。如图所示,\(A,B\) 两点的欧几里得距离为 \(c\),曼哈顿距离为 \(a+b\)

image

根据中学数学知识,我们知道:因为图中 \(a,b,c\) 所围成的三角形是直角三角形(由曼哈顿距离的定义可得知),所以 \(a+b>c\),而这与我们的题意是相悖的。

所以,当点 \(A,B\) 可围成一个三角形时,这个点对一定是不满足题意的。所以,我们可以得知:满足题意的点对,一定位于同一条平行于 \(x\) 轴或平行于 \(y\) 轴的直线上。

为统一做法,后文我们在构造的过程中,将所有符合条件的点对设置在同一条平行于 \(y\) 轴的直线上。

这样一来,这道题就变成了:设置 \(g\) 条平行于 \(y\) 轴且互相平行的直线 \(l_1,l_2,\dots,l_g\),在直线 \(l_i\) 上取 \(s_i\) 个点,使得 \(\sum s_i\le 500\)\(\sum\dfrac{s_i(s_i+1)}{2}=k\)(线段数求和公式,这个是初一数学内容,这里不再赘述)。

我们可以使用一个 while 循环,设置 \(x,y,t,tt\) 变量,其中 \(x\) 既代表了 \(l_x\),也代表了当前点的 \(x\) 坐标;\(y\) 代表当前点的 \(y\) 坐标;\(t\) 是直线 \(l_x\) 上目前的点数;\(tt\) 是一共设置了多少个点(即输出的 \(n\))。通过这种方式来得出每条直线上的点数以及具体坐标。最后输出即可。

参考代码

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

const int INF=0x3f;
const double EPS=1e-8;

template<typename T=int>
T rd(){
    char ch=getchar();
    T x=0,f=1;
    while(!isdigit(ch)){
        if(ch=='-') f*=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        x=(x<<3)+(x<<1)+(ch^48);
        ch=getchar();
    }
    return x*f;
}

void solve(){
    int k;
    cin>>k;
    set<ll> se;
    ll x=1,y=1,t=0,tt=0,s=k;
    queue<pii> q;
    while(s>0){
        if(se.count(y)){
            y+=x;
            continue;
        }
        se.insert(y);
        q.push({x,y});
        s-=t;
        y+=x;
        t++;
        tt++;
        if(t>s){
            t=0;
            x++;
            y=1;
        }
    }
    cout<<tt<<endl;
    while(!q.empty()){
        cout<<q.front().first<<" "<<q.front().second<<endl;
        q.pop();
    }
}

int main(){
    cin.tie(nullptr)->sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}
posted @ 2026-01-23 21:24  EnjoySilence  阅读(3)  评论(0)    收藏  举报