NC20066. [HNOI2008]水平可见直线
描述
输入描述
第一行为N(0 < N < 50000),接下来的N行输入Ai,Bi
输出描述
从小到大输出可见直线的编号,两两中间用空格隔开,最后一个数字后面也必须有个空格
示例1
输入:
3 -1 0 1 0 0 0
输出:
1 2
C++14(g++5.4) 解法, 执行用时: 36ms, 内存消耗: 11488K, 提交时间: 2019-08-18 12:45:07
#include<bits/stdc++.h> //CLOCKS_PER_SEC #define se second #define fi first #define ll long long #define Pii pair<int,int> #define Pli pair<ll,int> #define ull unsigned long long #define ALL(x) x.begin(),x.end() #define pb push_back #define mp make_pair #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) const int N=1e5+10; const int INF=0x3f3f3f3f; const int mod=1e9+7; using namespace std; typedef double db; const db eps=1e-6; const db pi=acos(-1); int sign(db k){ if (k>eps) return 1; else if (k<-eps) return -1; return 0; } int cmp(db k1,db k2){return sign(k1-k2);} int inmid(db k1,db k2,db k3){return sign(k1-k3)*sign(k2-k3)<=0;}// k3 在 [k1,k2] 内 struct point{ db x,y; point (db x=0, db y=0):x(x),y(y){} point operator + (const point &k1) const{return (point){k1.x+x,k1.y+y};} point operator - (const point &k1) const{return (point){x-k1.x,y-k1.y};} point operator * (db k1) const{return (point){x*k1,y*k1};} point operator / (db k1) const{return (point){x/k1,y/k1};} int operator == (const point &k1) const{return cmp(x,k1.x)==0&&cmp(y,k1.y)==0;} // 逆时针旋转 k1为弧度 point turn(db k1){return (point){x*cos(k1)-y*sin(k1),x*sin(k1)+y*cos(k1)};} point turn90(){return (point){-y,x};} bool operator < (const point k1) const{ int a=cmp(x,k1.x); if (a==-1) return 1; else if (a==1) return 0; else return cmp(y,k1.y)==-1; } db abs(){return sqrt(x*x+y*y);} db abs2(){return x*x+y*y;} db dis(point k1){return ((*this)-k1).abs();} point unit(){db w=abs(); return (point){x/w,y/w};} void scan(){double k1,k2; scanf("%lf%lf",&k1,&k2); x=k1; y=k2;} void print(){printf("%.11lf %.11lf",x,y);} db getw(){return atan2(y,x);} //极角 point getdel(){if (sign(x)==-1||(sign(x)==0&&sign(y)==-1)) return (*this)*(-1); else return (*this);} int getP() const{return sign(y)==1||(sign(y)==0&&sign(x)==-1);} }; int inmid(point k1,point k2,point k3){return inmid(k1.x,k2.x,k3.x)&&inmid(k1.y,k2.y,k3.y);}//判断k3在k1和k2组成的矩形里面 db cross(point k1,point k2){return k1.x*k2.y-k1.y*k2.x;} db dot(point k1,point k2){return k1.x*k2.x+k1.y*k2.y;} db rad(point k1,point k2){return atan2(cross(k1,k2),dot(k1,k2));}//有方向 int clockwise(point k1,point k2,point k3){// k1 k2 k3 逆时针 1 顺时针 -1 否则 0 return sign(cross(k2-k1,k3-k1)); } int onS(point k1,point k2,point q){return inmid(k1,k2,q)&&sign(cross(k1-q,k2-k1))==0;} db area(vector<point> A){ // 多边形用 vector<point> 表示 , 逆时针输入返回正,否则为负 db ans=0; for (int i=0;i<A.size();i++) ans+=cross(A[i],A[(i+1)%A.size()]); return ans/2; } int intersect(db l1,db r1,db l2,db r2){ if (l1>r1) swap(l1,r1); if (l2>r2) swap(l2,r2); return cmp(r1,l2)!=-1&&cmp(r2,l1)!=-1; } point getLL(point k1,point k2,point k3,point k4){ db w1=cross(k1-k3,k4-k3),w2=cross(k4-k3,k2-k3); return (k1*w2+k2*w1)/(w1+w2); } int checkSS(point k1,point k2,point k3,point k4){//线段和线段 若将两个<=改成< 则为非严格相交 return intersect(k1.x,k2.x,k3.x,k4.x)&&intersect(k1.y,k2.y,k3.y,k4.y)&& sign(cross(k3-k1,k4-k1))*sign(cross(k3-k2,k4-k2))<0&& sign(cross(k1-k3,k2-k3))*sign(cross(k1-k4,k2-k4))<0; } struct li{ db k, b; int id; point x, y; bool operator < (const li &oth) const{ if(k == oth.k){ return b > oth.b; } return k < oth.k; } }p[N]; li sta[N]; bool check(li x, li y, li z){ point a = getLL(x.x, x.y, z.x, z.y); point l1 = y.x, l2 = y.y; point vec = l2 - l1; l1 = l1 - vec*100000; l2 = l2 + vec*100000; if(l1.x < l2.x) swap(l1, l2); if(onS(l1, l2, a) || clockwise(a, l1, l2) == 1) return 1; return 0; } int main(){ int n; scanf("%d", &n); for(int i = 1; i <= n; ++i){ scanf("%lf%lf", &p[i].k, &p[i].b); p[i].id = i; p[i].x = point(0, p[i].b); if(p[i].k)p[i].y = point(1.0*p[i].k, p[i].k*p[i].k+p[i].b); else p[i].y = point(1, p[i].b); } sort(p+1, p+1+n); int top = 1; sta[top] = p[1]; for(int i = 2; i <= n; ++i){ if(p[i].k == p[i-1].k) continue; while(top >= 2 && check(sta[top], sta[top-1], p[i])) top--; sta[++top] = p[i]; } vector<int>ans; for(int i = 1; i <= top; ++i) ans.pb(sta[i].id); sort(ALL(ans)); for(auto i : ans){ printf("%d ", i); } return 0; }
C++ 解法, 执行用时: 41ms, 内存消耗: 920K, 提交时间: 2021-10-09 20:34:51
#include <map> #include <set> #include <cmath> #include <stack> #include <queue> #include <cstdio> #include <vector> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define ll long long struct Line { int a, b, id; } line[50010]; bool cmp(Line x, Line y) { return x.a != y.a ? x.a > y.a : x.b > y.b; } int top, ans[50010], st[50010]; double calc(int x, int y) { return (double)(line[x].b - line[y].b) / (double)(line[y].a - line[x].a); } int main() { int n; cin >> n; for (int i = 1; i <= n; i++) { cin >> line[i].a >> line[i].b; line[i].id = i; } sort(line + 1, line + n + 1, cmp); for (int i = 1; i <= n; i++) { if (line[i].a == line[i - 1].a && i != 1) continue; while (top > 1 && calc(st[top], i) >= calc(st[top], st[top - 1])) top--; st[++top] = i; ans[top] = line[i].id; } sort(ans + 1, ans + top + 1); for (int i = 1; i <= top; i++) cout << ans[i] << ' '; }