Codeforces Round #331 (Div. 2)——C. Wilbur and Points

本文介绍了一种算法竞赛中的题目解决方案,该问题要求合理安排坐标点的标号,确保满足特定条件的同时,每个点的权值也符合要求。文章详细解释了解题思路与实现步骤,包括坐标点的排序、权值的处理以及如何验证最终方案的有效性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MD,又因为一个傻逼错误搞了一个下午+一个晚上。。忧桑= =

题意:

现在有n个点,然后给出n个点的x,y坐标。然后这些坐标必须满足条件:比如说分配给点(x,y)的标号是i,那么点(x',y')的标号就必须是大于i的(这里x'>=x 或者 y'>=y 或者 x'>=x&&y'>=y)

然后给你n个的权值w[i],并且告诉你n个点的权值的计算公式是: s(xi, yi) = yi - xi = wi

然后让你安排n个点的标号,使它们在同时满足标号原则的前提下,并且使得第i个点的权值刚好满足w[i]。

思路:

比赛的时候没想到怎么给它们分配标号,参考了题解,很简单啊,首先先给它们进行排序,先按x值从小到大排,若x值相等,那么就按照y值从小到大排。然后,就是把权值为w[i]的点的坐标全都存下来,再来分配就好啦。

然后,判断是否符合标号原则,我们记arr[i][j]为权值为i的点集合中第j个点的序号,然后让它去与arr[i+1][j]和arr[i][j+1]去判断就好了。这里注意要判断arr[i+1],arr[j+1]这个集合是否为空,如果为空的那么这个点就不要判断了。

这题可能w[i]为负,所以我的办法是把它们全都进行平移10000个单位,相当于移动了坐标系。

噢,这题还有许多关于STL的用法,STL用的好的话真是十分方便的呢。还有pair函数,哈哈,第一次用呢。

#include<cstdio>
#include<cstring>
#include<map>
#include<set>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<iostream>
using namespace std;
typedef __int64 ll;
typedef unsigned __int64 ULL;
#define inf 99999999
#define add 100000
#define maxn 200022
int w[maxn];
struct node{
    int x,y;
    int idx;
    node(){}
    node(int xx,int yy){
        x=xx;
        y=yy;
    }
    friend bool operator <(node a,node b){
        if(a.x!=b.x) return a.x<b.x;
        else return a.y<b.y;
    }
};
map<int,int> mp;
set<node> st[maxn];
set<node>::iterator it;
vector<int> dian[maxn];
vector<int> ans[maxn];
pair<int,int> par[maxn];
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        st[y-x+add].insert(node(x,y));
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&w[i]);
        dian[w[i]+add].push_back(i);
    }
    for(int i=1;i<=n;i++){
        if(st[w[i]+add].size()!=dian[w[i]+add].size()){
            printf("NO\n");
            return 0;
        }
    }
    node tmp;
    for(int i=1;i<=n;i++){
        it=st[w[i]+add].begin();
        tmp=*it;
        int xx=(*it).x,yy=(*it).y;
        int idx=dian[w[i]+add][mp[w[i]+add]];
        par[idx]=make_pair(xx,yy);
        ans[xx].push_back(yy);
        int len=ans[xx].size()-1;
        ans[xx][len]=idx;
        st[w[i]+add].erase(tmp);
        mp[w[i]+add]++;
    }
    for(int i=0;i<100010;i++){
        for(int j=0;j<ans[i].size();j++){
            if(ans[i+1].size()>j&&ans[i+1][j]<ans[i][j]){
                printf("NO\n");
                return 0;
            }
            if(j+1<ans[i].size()&&ans[i][j]>ans[i][j+1]){
                printf("NO\n");
                return 0;
            }
        }
    }
    printf("YES\n");
    for(int i=1;i<=n;i++){
        printf("%d %d\n",par[i].first,par[i].second);
    }
    return 0;
}
/*
9
0 0
1 0
2 0
0 1
1 1
2 1
1 2
2 2
0 2
0 0 0 -1 -1 -2 1 1 2
*/

加油!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值