题目传送门
题意解析:题目给了你n个数轴上的点和每个点上的权值,以abs(x[i]-x[j])>=w[i]+w[j]为要求建图,求最大的完全图。
My opinion:题目乍一看很迷,可能认为是图论的题目,然而这个条件——abs(x[i]-x[j])>=w[i]+w[j]可以发现一个转换,x[i],w[i]可以看成是一条线段,左右端点分别为x[i]-w[i],x[i]+w[i],然后这个条件就是两条线段互不相交(线段端点重合是算作不相交的)。所以题目最后就是问给你n条线段,然后问两两互不相交的线段条数(这种题应该都碰到过)。这样就很明显可以使用dp了,之后用二分优化dp变成O(nlgn)就可以了。
总结:
1、输入。
2、dp+二分
f[i]表示两两互不相交的线段为i条的最小右端点。
3、输出。
代码(听说贪心也可以):
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=a;i>=n;i--)
#define Clear(a,x) memset(a,x,sizeof(a))
#define ll long long
#define INF 2000000000
#define eps 1e-8
using namespace std;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9') f=ch=='-'?-1:f,ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int maxn=200005;
int n,ans;
struct node{
int x,w;
void Read(){
x=read(),w=read();
}
}a[maxn];
int f[maxn];
bool cmp(node a,node b){
if (a.x-a.w==b.x-b.w) return a.x+a.w<b.x+b.w;
else return a.x-a.w<b.x-b.w;
}
int bs(int l,int r,int k){
while (l<r){
int mid=(l+r)>>1;
if (f[mid]>k) r=mid;
else l=mid+1;
}
return l;
}
int main(){
n=read();
rep(i,1,n) a[i].Read();
sort(a+1,a+n+1,cmp);
f[0]=-INF;
rep(i,1,n) f[i]=INF;
rep(i,1,n){
int j=bs(0,n,a[i].x-a[i].w);
f[j]=min(f[j],a[i].x+a[i].w);
ans=max(ans,j);
}
printf("%d\n",ans);
return 0;
}