【DP+树状数组 or 贪心】Codeforces527D[Clique Problem]题解

来源:互联网 发布:php函数大全怎么记忆 编辑:程序博客网 时间:2024/06/17 18:15

题目概述

给出平面上 n 个点 xi ,每个点有个权值 wi(wi>0) ,当 |xixj|wi+wjij 有条边。求最大团(最大完全子图)。

解题报告

先将点按照位置排序,然后会发现若 k<j<ik 能到 jj 能到 i ,则 k 一定能到 i 。证明很简单:

xjxkwk+wj,xixjwj+wixixkwi+2wj+wkwi+wk

所以一条链上的点均能互相到达成为团,那么现在求最大团等价于求最长链。

DP一下就好了,离散之后用树状数组优化。

实际上推到这里发现每个点可以抽象成线段,用贪心求最多的不相交线段即可,详细点?不如Orz CHNJZ。

示例程序

#include<cstdio>#include<algorithm>#define fr first#define sc secondusing namespace std;const int maxn=200000;int n,A[maxn+5],B[maxn+5],a[maxn*2+5],c[maxn*2+5];pair<int,int> p[maxn+5];inline int Find(int x){    int L=1,R=a[0];    for (int mid=L+(R-L>>1);L<=R;mid=L+(R-L>>1)) if (a[mid]<=x) L=mid+1; else R=mid-1;    return R;}inline void Update(int x,int tem) {for (int i=x;i<=a[0];i+=i&-i) c[i]=max(c[i],tem);}inline int Max(int x) {int MAX=0;for (int i=x;i;i-=i&-i) MAX=max(MAX,c[i]);return MAX;}int main(){    freopen("program.in","r",stdin);    freopen("program.out","w",stdout);    scanf("%d",&n);    for (int i=1;i<=n;i++) scanf("%d%d",&p[i].fr,&p[i].sc);sort(p+1,p+1+n);    for (int i=1;i<=n;i++) a[++a[0]]=p[i].fr-p[i].sc,a[++a[0]]=p[i].fr+p[i].sc;    sort(a+1,a+1+a[0]);a[0]=unique(a+1,a+1+a[0])-a-1;    for (int i=1;i<=n;i++) A[i]=Find(p[i].fr-p[i].sc),B[i]=Find(p[i].fr+p[i].sc);    for (int i=1;i<=n;i++) Update(B[i],Max(A[i])+1);    return printf("%d\n",Max(a[0])),0;}
阅读全文
0 0
原创粉丝点击