• 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
    ",ans);
    122     return 0;
    123 }
  • 相关阅读:
    JAVA获取随机数
    web路径问题
    java.lang.IllegalStateException: Failed to load ApplicationContext,这个异常的解决方案
    使用表达式配置切入点
    Spring的aop操作
    AOP操作术语
    AOP原理
    AOP概念
    spring知识点
    Spring的ioc操作 与 IOC底层原理
  • 原文地址:https://www.cnblogs.com/LI-dox/p/11227904.html
Copyright © 2020-2023  润新知