传送门
SOL
注意看清楚题面: y ≥ 0 y\ge0 y≥0
可以以点为单位转移,也可以像我这样以边为单位转移。
按边的极角排序,用vector d[i]存下以i点为终点的所有线段,每次枚举线段用dp转移即可。
d
p
[
i
]
=
m
a
x
(
d
p
[
j
]
)
+
v
a
l
[
i
]
dp[i]=max(dp[j])+val[i]
dp[i]=max(dp[j])+val[i]
以边为单位,代码丑。。
可以以点为单位,预处理原点与另外两点的三角形的代价,每次枚举前两个点转移,代码50行不到。。
时间复杂度:O(n^3)
可以用平衡树维护极角序列,第三维实现 O{log)查询;
复杂度:O(n^2log)
CODE
这个代码丑。。找个时间补一个平衡树O(n^2logn)算法;
#include<bits/stdc++.h>
using namespace std;
#define sf scanf
#define pf printf
#define ll long long
#define db double
#define cs const
cs int N=2e4+10,lowf=-2139062144;
cs db eps=1e-8,pi2=acos(-1)*2,pi=acos(-1);
inline bool equal(cs db &a,cs db &b){return abs(a-b)<eps;}
inline bool eles(cs db &a,cs db &b){return equal(a,b)|a<b;}
struct Vector{
ll x,y;
Vector (ll x=0,ll y=0):x(x),y(y){}
friend Vector operator +(cs Vector &a,cs Vector &b){return Vector(a.x+b.x,a.y+b.y);}
friend Vector operator -(cs Vector &a,cs Vector &b){return Vector(a.x-b.x,a.y-b.y);}
friend ll operator ^(cs Vector &a,cs Vector &b){return a.x*b.y-a.y*b.x;}
friend ll operator *(cs Vector &a,cs Vector &b){return a.x*b.x+a.y*b.y;}
friend bool operator ==(cs Vector &a,cs Vector &b){return a.x==b.x&&a.y==b.y;}
}p[N],ch[N];
struct Line{
Vector st,ed;
int id,id2;
db ang;
bool operator <(cs Line &t)cs{
return ang<t.ang;
}
};
int n,m,cnt=0,dp[N];
Line l[N];
vector <int> d[N];
inline db lenth(cs Vector &a){
return sqrt(a.x*a.x+a.y*a.y);
}
inline bool check(cs Vector &p0,cs Vector &a,cs Vector &b,cs Vector &c){
db a1=acos(((a-p0)*(b-p0))/(lenth(a-p0)*lenth(b-p0)));
db a2=acos(((b-p0)*(c-p0))/(lenth(b-p0)*lenth(c-p0)));
db a3=acos(((c-p0)*(a-p0))/(lenth(a-p0)*lenth(c-p0)));
if(equal(a1+a2+a3,pi2))return 1;
return 0;
}
inline int calc(cs int &k){
int ans=0;
for(int i=1;i<=n;++i)if(check(p[i],Vector(0,0),l[k].st,l[k].ed))++ans;
for(int i=1;i<=m;++i)if(check(ch[i],Vector(0,0),l[k].st,l[k].ed))--ans;
return ans;
}
int ans=0;
signed main(){
memset(dp,128,sizeof dp);
sf("%d%d",&n,&m);
for(int i=1;i<=n;++i)sf("%lld%lld",&p[i].x,&p[i].y);
for(int i=1;i<=m;++i)sf("%lld%lld",&ch[i].x,&ch[i].y);
p[0].x=p[0].y=0;
for(int i=0;i<=n;++i){
for(int j=0;j<=n;++j){
if(i^j){
db ang;
if(p[i].y^p[j].y){
ang=atan2(p[j].y-p[i].y,p[j].x-p[i].x);
if(eles(ang,0))ang+=pi2;
}
else {
ang=p[i].x<p[j].x? 0 : pi;
}
l[++cnt]=(Line){p[i],p[j],i,j,ang};
}
}
}
sort(l+1,l+cnt+1);
for(int i=1;i<=cnt;++i)d[l[i].id2].push_back(i);
for(int i=1;i<=cnt;++i){
if(l[i].st==Vector(0,0)){
dp[i]=1;
continue;
}
int up=d[l[i].id].size(),d2=lowf;
for(int j=0;j<up;++j){
if(dp[d[l[i].id][j]]==lowf)continue;
d2=max(d2,dp[d[l[i].id][j]]);
}
if(d2==lowf)continue;
int d1=calc(i);
dp[i]=d1+d2+1;
if(l[i].ed==p[0])ans=max(ans,dp[i]-1);
}
cout<<ans;
return 0;
}