GYM 101606 L.Lounge Lizards(计算几何+LIS)

Description

给出二维空间 n 个点及其权值,问从起点开始,各个方向的射线上的点构成的序列的严格最长上升子序列长度之和

Input

首先输入两个整数 x 0 , y 0 表示起点坐标,然后输入一整数 n 表示点数,之后 n 行每行三个整数 x i , y i , h i 表示第 i 个点的坐标和权值

( 10 6 x 0 , y 0 , x i , y i 10 6 , 1 n , h i 10 6 )

Output

输出各个方向上严格最长上升子序列长度之和

Sample Input

50 50
2
60 50 1
65 50 2

Sample Output

2

Solution

把每个方向上的点按其离起点距离排序,对排序后这些点的权值序列求 L I S 累加即可

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
typedef pair<ll,int>PP;
const int INF=0x3f3f3f3f,maxn=1000005;
map<P,int>m; 
int xx,yy,n,res,cnt,a[maxn],dp[maxn];
vector<PP>g[maxn];
int gcd(int a,int b)
{
    return b?gcd(b,a%b):a;
}
ll dis(int x,int y)
{
    return (ll)x*x+(ll)y*y;
}
void deal(int x,int y,int h)
{
    ll d=dis(x,y);
    if(x==0)y/=abs(y);
    else if(y==0)x/=abs(x);
    else
    {
        int z=gcd(abs(x),abs(y));
        x/=z,y/=z;
    }
    if(m.find(P(x,y))==m.end())m[P(x,y)]=++res;
    g[m[P(x,y)]].push_back(PP(d,h));
}
int Solve(int n,int *a)
{
    for(int i=1;i<n;i++)dp[i]=INF;
    dp[0]=a[0];
    int len=1;
    for(int i=1;i<n;i++)
    {
        if(a[i]>dp[len-1])
            dp[len++]=a[i];
        else
            dp[lower_bound(dp,dp+n,a[i])-dp]=a[i]; 
    }
    return len;
}
int main()
{
    scanf("%d%d",&xx,&yy);
    scanf("%d",&n);
    res=0;
    for(int i=1;i<=n;i++)
    {
        int x,y,h;
        scanf("%d%d%d",&x,&y,&h);
        x-=xx,y-=yy;
        deal(x,y,h);
    }
    int ans=0;
    for(int i=1;i<=res;i++)
    {
        sort(g[i].begin(),g[i].end());
        cnt=g[i].size();
        for(int j=0;j<cnt;j++)a[j]=g[i][j].second;
        ans+=Solve(cnt,a);
    }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/v5zsq/article/details/80472502