zoukankan      html  css  js  c++  java
  • USACO 2016 February Contest Gold T3: Fenced In

    题目大意

    有一个平面,左下角是(0,0),右上角是(A,B)。

    有n个平行于y轴的栅栏a1..an,表示挡在(ai,0)到(ai,B)之间。有m个平行于x轴的栅栏b1..bn,表示挡在(0,bi)到(A,bi)之间。

    这样,平面被划成了(n+1)*(m+1)块。现在要去掉某些栅栏的一部分,使得每一块都连通。

    (0≤n,m25,000)

    比如原来是这样:

    +---+--+

    |     |    |

    +---+--+

    |     |    |

    |     |    |

    +---+--+

    可以去掉后变成这样:

    +---+--+

    |          |

    +---+   +

    |          |

    |          |

    +---+--+

    题目分析

    看到“去掉某些栅栏的一部分,使得每一块都连通”,不难联想到最小生成树。然而观察数据范围, n,m最大可达2e5,这样分出来的块数可能多达 2e5*2e5 , 若是再排个序的话,复杂度肯定会爆炸,所以考虑优化。

    由于每一条围栏都是平行于所对应的边框的,所以,同一列的水平围栏长度相同,同一行的竖直围栏也长度相等。

    这样就可以把水平围栏和竖直围栏分开算了,贪心地直接删去整行或整列。

    但是,在删的过程中,由于到后面,并不是一整行或一整列上所有的围栏都要删去,有的删去甚至会出现环路,所以......

    用x数组记录水平围栏的长度,用y数组记录竖直围栏的长度。再用i,j两个指针记录当前扫到第几行或列。

    当i,j都大于1的时候:

    由于当x[i]<y[j]的时候,肯定要删第i列的水平栅栏,该列的栅栏个数为m(行数)-j(已经删了多少行)+1,对列有影响的是行(列与列不相交)

    当x[i]>y[j]的时候,肯定要删第j行的竖直栅栏,该行的栅栏个数为n(列数)-i(已经删了多少列)+1,对行有影响的是列(行与行不相交)

    //不太理解可以自己画一个图

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int MAXN=2e5+10;
     4 typedef long long ll;
     5 
     6 ll A,B,n,m,ans;
     7 ll a[MAXN],b[MAXN];
     8 ll x[MAXN],y[MAXN];
     9 int main(){
    10     scanf("%lld%lld%lld%lld",&A,&B,&n,&m);
    11     for(int i=1;i<=n;++i)
    12         scanf("%lld",&a[i]);
    13     for(int i=1;i<=m;++i)
    14         scanf("%lld",&b[i]);
    15     sort(a+1,a+n+1);
    16     sort(b+1,b+m+1);
    17     for(int i=1;i<=n;++i)
    18         x[i]=a[i]-a[i-1];
    19     x[n+1]=A-a[n];
    20     for(int i=1;i<=m;++i)
    21         y[i]=b[i]-b[i-1];
    22     y[m+1]=B-b[m];
    23     
    24     ++n;++m;
    25     sort(x+1,x+n+1);
    26     sort(y+1,y+m+1);
    27     
    28 //    for(int i=1;i<=n;++i)
    29 //        cout<<x[i]<<' ';
    30 //    for(int i=1;i<=m;++i)
    31 //        cout<<y[i]<<' '; 
    32 //    puts("");
    33     ans=x[1]*(m-1)+y[1]*(n-1);
    34     for(int i=2,j=2;i<=n&&j<=m;){
    35         if(x[i]<y[j])
    36             ans+=x[i++]*(m-j+1);
    37         else 
    38             ans+=y[j++]*(n-i+1);
    39     //    cout<<ans<<endl;
    40     }
    41     printf("%lld
    ",ans);
    42     return 0;
    43 } 
  • 相关阅读:
    《算法竞赛入门经典》(刘汝佳)——排序与检索(基础)
    Python中的GIL
    MongoDB 安装
    python3 报错集合
    socket 实例化方法
    socket入门
    Day_6作业_模拟人生
    高阶函数举例
    面向对象_python
    xml
  • 原文地址:https://www.cnblogs.com/LI-dox/p/11218652.html
Copyright © 2011-2022 走看看