• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
旭日临窗
博客园    首页    新随笔    联系   管理    订阅  订阅
CF527D 题解

题意:数轴上有 \(n\) 个点,第 \(i\) 个点的坐标为 \(x_i\),权值为 \(w_i\)。两个点 \(i,j\) 之间存在一条边当且仅当 \(abs(x_i-x_j)\geq w_i+w_j\)​ 。 你需要求出这张图的最大团的点数。
团的定义:两两之间有边的顶点集合。

solution:
可以先从式子入手。\(i,j\) 两点之间有边的条件是 \(\left|x_i-x_j\right|\ge w_i+w_j\),然后考虑怎么把绝对值去掉,不妨设 \(x_i \ge x_j\),然后式子就化简为了 \(x_i-x_j \ge w_i+w_j\),遇到这种式子可以套路地把带有 \(i\) 的项移到一边,带有 \(j\) 的项移到另一边,所以式子就变成了:

\(x_i-w_i \ge x_j+w_j\) 在数轴上表示如图:

容易发现如果把一个点看成一条左端点为 \(x_k-w_k\),右端点为 \(x_k+w_k\) 的线段,那么两个点之间有边当且仅当两条线段不重合,再根据团的定义:每两个点之间都有边。就转化为了任意两条线段都不重合,所以问题就变成了从 \(n\) 条线段里选择尽可能多的线段,使得任意两条线段都不重合,也就是线段覆盖问题。这里有一道线段覆盖的模板题,可以先完成。

代码(可读性应该还可以吧):

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int n,ans;
struct node{
	int l,r;
	bool operator < (const node &w) const{return r < w.r;}
}a[maxn];
int main(){
	scanf("%d",&n);
	int x,y;
	for(int i = 1;i <= n;i++){
		scanf("%d%d",&x,&y);
		a[i] = node{x - y,x + y};
	}
	sort(a + 1,a + n + 1);
	int nr = -2e9;
	for(int i = 1;i <= n;i++)
	if(a[i].l >= nr) nr = a[i].r,ans++;
	printf("%d",ans);
	return 0;
}
posted on 2022-01-27 10:14  旭日临窗  阅读(49)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3