题解:P11023 [COTS 2020] 王国 Kraljevstvo
andychen_2012 · · 题解
对于
对于
其中
对于
注意到这相当于
因此我们四边形优化 dp 即可。
代码如下:
const int N=3005;
const int inf=1e9;
int n,k;
struct point{ll x,y;}p1[N],p2[N],p[N];
int sz1,sz2,sz;
inline bool cmp1(point a,point b){return a.x^b.x?a.x<b.x:a.y<b.y;}
inline bool cmp2(point a,point b){return a.x^b.x?a.x>b.x:a.y>b.y;}
ll f[N][N];
ll mx1[N],mx2[N];
inline ll area(point a,point b,point c){
ll x1=b.x-a.x,y1=b.y-a.y;
ll x2=c.x-a.x,y2=c.y-a.y;
return x1*y2-x2*y1;
}
inline void DP(int id,int l,int r,int pl,int pr){
if(l>r) return;
int mid=(l+r)>>1;
int opt=l;
for(int i=pl;i<=pr;++i){
if(i>=mid) break;
ll cost=f[id-1][i]+area(p[i],p[1],p[mid]);
// printf("area(%d,%d,%d)=%lld\n",0,i-1,mid-1,area(p[i],p[1],p[mid]));
if(cost>=f[id][mid]){
f[id][mid]=cost;
opt=i;
}
}
DP(id,l,mid-1,pl,opt);
DP(id,mid+1,r,opt,pr);
}
int main(){
// freopen("input.txt","r",stdin);
// freopen("1.out","w",stdout);
n=read(),k=read();
for(int i=1,x,y;i<=n;++i){
x=read(),y=read();
p[++sz]={x,y};
}
sort(p+1,p+sz+1,cmp1);
for(int i=1;i<=sz;++i){
while(sz1>=2&&area(p1[sz1-1],p1[sz1],p[i])>=0)
--sz1;
p1[++sz1]=p[i];
}
reverse(p+1,p+sz+1);
for(int i=1;i<=sz;++i){
while(sz2>=2&&area(p2[sz2-1],p2[sz2],p[i])>=0)
--sz2;
p2[++sz2]=p[i];
}
// reverse(p2+1,p2+sz2+1);
// for(int i=1;i<=sz1;++i) printf("%lld %lld\n",p1[i].x,p1[i].y);
// puts("");
// for(int i=1;i<=sz2;++i) printf("%lld %lld\n",p2[i].x,p2[i].y);
// puts("");
sz=sz1;
for(int i=1;i<=sz;++i) p[i]=p1[i];
f[0][1]=0;
for(int i=2;i<=sz;++i) f[0][i]=-(1ll<<60);
for(int i=1;i<=k;++i){
for(int j=0;j<=sz;++j) f[i][j]=0;
DP(i,1,sz,1,sz);
mx1[i]=f[i][sz];
}
sz=sz2;
for(int i=1;i<=sz;++i) p[i]=p2[i];
f[0][1]=0;
for(int i=2;i<=sz;++i) f[0][i]=-(1ll<<60);
for(int i=1;i<=k;++i){
for(int j=0;j<=sz;++j) f[i][j]=0;
DP(i,1,sz,1,sz);
mx2[i]=f[i][sz];
}
ll ans=0;
for(int i=1;i<=k&&i<=sz1;++i){
for(int j=1;i+j<=k&&j<=sz2;++j)
ans=max(ans,mx1[i]+mx2[j]);
}
if(ans&1) printf("%lld.5\n",ans/2);
else printf("%lld\n",ans/2);
return 0;
}