1. 程式人生 > >Gym 101606L - Lounge Lizards - [計算幾何+LIS]

Gym 101606L - Lounge Lizards - [計算幾何+LIS]

代碼 bool 題目 ref lse 序列 back truct 題解

題目鏈接:https://codeforces.com/gym/101606/problem/L

題解:

在同一條線上的所有蜥蜴,他們的斜率都是相通的,換句話說可以直接通過斜率將蜥蜴分組。

每一組即代表一條直線上的所有蜥蜴,再將這條直線以TV點為分界分成兩條射線,這樣每條射線上的蜥蜴,按距離TV從近到遠,它們的身高排成一個整數序列,對這個序列求最長上升子序列即可。

需要註意的:

  DP求LIS的話是 $O(n^2)$ 的時間復雜度,是過不了的應該,要用貪心+二分 $O(n \log n)$ 求LIS長度;

  不確定直接用double類型存斜率是不是會有精度問題,可以用pair<int,int>類型當做分數類來表示斜率,註意約分就好了,還可以省去考慮直線平行坐標軸的問題。

AC代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn=1e6+10;

int n,X,Y;

int tot;
map<pii,int> mp;

struct Li
{
    ll dist;
    int h;
    bool operator<(const Li& o)const
    {
        return
dist<o.dist; } }; vector<Li> H[2][maxn]; inline pii grad(int x,int y) { int dx=x-X, dy=y-Y; int g=__gcd(dx,dy); return make_pair(dx/g,dy/g); } inline ll dist(ll x,ll y) { return (x-X)*(x-X)+(y-Y)*(y-Y); } inline bool check(int x,int y) { if(x==X) return
y>Y; else return x>X; } int S[maxn],top; int solve(const vector<Li>& a) { S[top=0]=a[0].h; for(int i=1;i<a.size();i++) { int pos=lower_bound(S,S+top+1,a[i].h)-S; S[pos]=a[i].h; top=max(top,pos); } return top+1; } int main() { cin>>X>>Y; cin>>n; mp.clear(), tot=0; for(int i=1,x,y,h;i<=n;i++) { scanf("%d%d%d",&x,&y,&h); pii g=grad(x,y); if(mp[g]==0) mp[g]=++tot; H[check(x,y)][mp[g]].push_back((Li){dist(x,y),h}); } int ans=0; for(int i=1;i<=tot;i++) { sort(H[0][i].begin(),H[0][i].end()); sort(H[1][i].begin(),H[1][i].end()); if(H[0][i].size()) ans+=solve(H[0][i]); if(H[1][i].size()) ans+=solve(H[1][i]); } cout<<ans<<endl; }

Gym 101606L - Lounge Lizards - [計算幾何+LIS]