clique 解题报告

clique

题目描述

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

输入数据

第一行一个整数 \(n\),接下来 \(n\) 行每行两个整数 \(x_i,w_i\)

输出数据

一行一个整数表示答案

数据范围

对于 \(20\%\) 的数据, \(n<=10\)
对于 \(60\%\) 的数据, \(n<=1000\)
对于 \(100\%\) 的数据, \(n<=200000\)\(0<=|x_i|,w_i<=10^9\)


考试的时候发现了一个性质

如果三个点按从左到右排,点1点2有边且点2点3右边可以得到点1点3有边

于是可以\(N^2\)连边跑topo最长路(从左到右连有向边)

想拿\(set\)优化连边但是没想到。

结果数组开小爆30了。

正解算是没想到吧。

如果把点看做形如\([x-w,x+w]\)的区间,那么两个点有连边等价于区间无交点。

于是问题转化成了不重合的区间数量

可以简单的贪心,也可以DP

复杂度都是\(O(nlogn)\)


Code:

#include <cstdio>
#include <algorithm>
const int N=2e5+10;
struct node
{
    int l,r;
    bool friend operator <(node n1,node n2){return n1.r<n2.r;}
}seg[N];
int rr[N],dp[N],f[N],pos[N],n;
int max(int x,int y){return x>y?x:y;}
int main()
{
    scanf("%d",&n);
    for(int x,w,i=1;i<=n;i++)
    {
        scanf("%d%d",&x,&w);
        seg[i].l=x-w,seg[i].r=x+w;
        rr[i]=seg[i].r;
    }
    std::sort(seg+1,seg+1+n);
    std::sort(rr+1,rr+1+n);
    rr[0]=seg[1].r-1;
    for(int i=1;i<=n;i++)
    {
        int l=0,r=i-1;
        while(l<r)
        {
            int mid=l+r+1>>1;
            if(seg[i].l>=rr[mid])
                l=mid;
            else
                r=mid-1;
        }
        pos[i]=l;
    }
    for(int i=1;i<=n;i++)
        dp[i]=f[pos[i]]+1,f[i]=max(f[i-1],dp[i]);
    printf("%d\n",f[n]);
    return 0;
}

2018.10.13

猜你喜欢

转载自www.cnblogs.com/ppprseter/p/9784029.html
今日推荐