USACO 2019 February Contest Platinum T3: Mowing Mischief

题目大意

Bessie的表妹Ella和Bella正在参观农场。不幸的是,自从他们到达以来,他们一直在恶作剧。

在他们的最新计划中,他们决定尽可能多地割草。农场的草地是 T×T 的正方形。左下角是 (0,0) ,右上角是 (T,T) 。因此,正方形包含 (T+1)2 个格点(具有整数坐标的点)。

Ella和Bella计划从 (0,0) 开始并以每秒一个单位长度的速度运行到 (T,T) ,同时每只奶牛都握住非常锋利且非常有弹性的线的一端。任何被这根电线扫过的区域的草都会被切断。Ella和Bella可能采取不同的路径,但她们只会向上或者向右移动,从一个格点移动到另一个格点。

Bessie非常担心会切割太多的草,所以她发明了一个聪明的计划来限制Ella和Bella的路径。在整个草原上散布着 种花(1N2e5),每种花都在一个特定的格点上。 Bessie将从这些花中挑选一个子集 S , S 集合中的花Ella和Bella都需要经过(Ella和Bella的路径都必须经过 S 中的所有花朵)。

Ella和Bella将会切割面积尽可能大的草,请帮助Bessie确定集合 SS 使得在 SS集合尽可能大的情况下被切割的草的面积最小。

题目分析

经过思考,我们发现骑士拉着线扫对Ella和Bella来说最优的情况就是划出一个矩形。

所以,问题变成了在 N 个点中选择某些点,排序后一一构成矩形(相邻的点),求构成的这些矩形的最小面积和。

 

将所有点按照其横坐标为第一关键字,纵坐标为第二关键字排序,靠前的点无法转移到靠后的点。用树状数组进行动态规划,我们可以得到以每个点为结尾的选取序列的最优长度。(相当于求以每个点结尾的LIS)并根据LIS的大小对点进行分层。

可以得出属于同一层的点横坐标递增,纵坐标递减。

 

接下来,我们只需要考虑层与层之间的转移。(本层点的LIS一定是由上一层点的LIS转移过来的)

转移方程如下:

 

dpi​ =Minj (j为上一层点 且 xjxiyjyi​ {dpj (xixj∗ (yiyj

把后一项拆开,得:

dpi​ =Minj (j为上一层点 且 xjxiyjyi​ {dpj xjyj​ − xiy− xjyi } +xiyi

考虑 j,k 两处转移,令 j的转移 优于 k  ,则

dpj​ xjyj​ − xiy− xjyi​  ≤ dpk​ xkyk​ − xiyk​ − xkyi

(ykyjxi+(xkxj)yi​ ≤ dpk​ xkykdpjxjyj

注意到 ykyj和 xkxj必然一正一负,因此这个半平面一定会将下一层的点分为前后两部分,因而若排除掉 xjxi,yjyi的限制,该 DP 的转移具有决策单调性。

那么,先用线段树分治处理转移,再用决策单调性优化转移即可。

时间复杂度  O(N log2N)

 

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 const int MAXN=3e5+10;
  5 const int MAXT=1e6+10;
  6 const ll Inf=1e18+7;
  7 struct Node{
  8     int x,y;
  9 }p[MAXN];
 10 inline bool cmpx(Node a,Node b){return a.x==b.x?a.y<b.y:a.x<b.x;}
 11 
 12 int T,n,m,s;
 13 int layer[MAXN];
 14 ll dp[MAXN];
 15 int BIT[MAXT];
 16 vector<int> pos[MAXN];
 17 inline int lowbit(int x){return x&(-x);}
 18 inline void Modify(int x,int v){for(int i=x;i<=T;i+=lowbit(i)) BIT[i]=max(BIT[i],v);}
 19 inline int Query(int x){int res=0;for(int i=x;i;i-=lowbit(i))res=max(res,BIT[i]);return res;}
 20 
 21 struct Segment_Tree{
 22     struct Node{
 23         int ls,rs;
 24         vector<int> trans;
 25     }a[MAXN<<1];
 26     
 27     int n,size,rt;
 28     vector<int> point,tmp;
 29     
 30     inline void Build(int &rt,int l,int r){
 31         rt=++size;
 32         a[rt].ls=a[rt].rs=0;
 33         a[rt].trans.clear();
 34         if(l==r) return;
 35         int mid=(l+r)>>1;
 36         Build(a[rt].ls,l,mid);
 37         Build(a[rt].rs,mid+1,r);
 38     }
 39     inline void Init(vector<int> tmp){
 40         point=tmp;
 41         n=tmp.size();
 42         rt=size=0;
 43         Build(rt,0,n-1);
 44     }
 45     inline void Modify(int rt,int l,int r,int x){
 46         if(p[x].x>=p[point[r]].x&&p[x].y>=p[point[l]].y){
 47             a[rt].trans.push_back(x);
 48             return;
 49         }
 50         if(p[x].x<=p[point[l]].x||p[x].y<=p[point[r]].y) return;
 51         int mid=(l+r)>>1;
 52         Modify(a[rt].ls,l,mid,x);
 53         Modify(a[rt].rs,mid+1,r,x);
 54     }
 55     inline void modify(int x){
 56         Modify(rt,0,n-1,x);
 57     }
 58     
 59     inline void Solve(int l,int r,int ql,int qr){
 60         ll ans=Inf;int from=0;
 61         int mid=(l+r)>>1,now=tmp[mid];
 62         for(int i=ql;i<=qr;++i){
 63             int pos=point[i];
 64             ll res=dp[pos]+1ll*(p[now].x-p[pos].x)*(p[now].y-p[pos].y);
 65             if(res<ans){
 66                 ans=res;
 67                 from=i;
 68             }
 69         }
 70         dp[now]=min(dp[now],ans);
 71         if(l<mid) Solve(l,mid-1,from,qr);
 72         if(mid<r) Solve(mid+1,r,ql,from);
 73     }
 74     inline void Work(int rt,int l,int r){
 75         if(a[rt].trans.size()){
 76             tmp=a[rt].trans;
 77             Solve(0,tmp.size()-1,l,r);
 78         }
 79         if(l==r) return;
 80         int mid=(l+r)>>1;
 81         Work(a[rt].ls,l,mid);
 82         Work(a[rt].rs,mid+1,r);
 83     }
 84     inline void work(){
 85         Work(rt,0,n-1);
 86     }
 87 }ST;
 88 int main(){
 89     scanf("%d%d",&n,&T);
 90     for(int i=1;i<=n;++i)
 91         scanf("%d%d",&p[i].x,&p[i].y);
 92     sort(p+1,p+n+1,cmpx);
 93     
 94     for(int i=1;i<=n;++i){
 95         layer[i]=Query(p[i].y)+1;
 96         Modify(p[i].y,layer[i]);
 97         pos[layer[i]].push_back(i);
 98         m=max(m,layer[i]);
 99         //cout<<layer[i]<<' ';
100     }
101     //cout<<111<<endl;
102     for(int i=0,now;i<(int)pos[1].size();++i){
103         now=pos[1][i];
104         dp[now]=1ll*p[now].x*p[now].y;
105     }
106     for(int i=2,now;i<=m;++i){
107         ST.Init(pos[i-1]);
108         for(int j=0;j<(int)pos[i].size();++j){
109             now=pos[i][j];
110             dp[now]=Inf;
111             ST.modify(now);
112         }
113         ST.work();
114     }
115     ll ans=Inf;
116     //cout<<111<<endl;
117     for(int i=0;i<(int)pos[m].size();++i){
118         int now=pos[m][i];
119         ans=min(ans,dp[now]+1ll*(T-p[now].x)*(T-p[now].y));
120     }
121     printf("%lld\n",ans);
122     return 0;
123 }

 

posted @ 2019-07-22 19:28  LI_dox  阅读(465)  评论(0编辑  收藏  举报