zoukankan      html  css  js  c++  java
  • NOIP 普及组 2016 海港

    传送门

    https://www.cnblogs.com/violet-acmer/p/9859003.html

     这次比赛,上来还是死抠第一题,用了一个半小时才 AC,还是太菜了..................

    题意

      一共有 n 艘船,每艘船都有一个到港时间,每艘船上有 k 个人,这 k 个人可能来自多个不同的国家;

      求以当前船只为终了时间,在这之前的 24 小时内,到港的所有船只中所承载的乘客来自多少个国家?


    题解

    •相关变量解释

    • arrive[maxn]........................................arrive[ i ] : 第 i 艘船到港的时间
    • affect[maxn].........................................affect[ i ] : i 国籍为所影响的范围,但不包括其本身
    • vector<int >ship[maxn].........................ship[ i ] : 第 i 艘船上所承载的乘客国籍信息
    • diff[maxn].............................................差分数组 

      因为 k1+k2+.......+k2 ≤ 3×105,所以用vector存不会超内存。

    去重

      因每艘船的 k 个人可能有来自同一国家的乘客,所以先去一下重

      sort(ship[i].begin(),ship[i].end());

      ship[i].erase(unique(ship[i].begin(),ship[i].end()),ship[i].end());

    找到每艘船的乘客所能影响的最大范围

      这是什么意思呢?

      例如,第一艘船去重后,乘客分别来自 1,2,4 国家;

      由于所要求得是以当前船只为终了时间,在这之前的 24 小时内,到港的所有船只中所承载的乘客来自多少个国家;

      换句话说,当前船只的乘客只能影响这之后的 24 小时内到达的船只(不包含第 24 小时到达的船只)。

      所以第一艘船的 1 乘客的影响范围为[1,1+86400),此时,记 affect[1]=1+86400,但 1 所影响的范围不包括 affect[1] 本身;

      同理,第 2,4 乘客的影响范围也为[1,1+86400)

      当来到第二艘船的时候,去重后,乘客分别来自 2,3 国家,而当前船只到港时间为 2 ,affect[2]=1+86400 > 2,

      所以受之前船只的影响,国籍为 2 的乘客并不会对[2,1+86400)造成影响,而当前的 2 乘客可以影响的范围为 [2,2+86400),

      所以需要在之前的范围[1,1+86400)上加上范围[1+86400,2+86400),即加上[affect[2], 2+86400),并将affect[2]更新为2+86400。

    •求解

      但要如何记录以当前船只为终了时间的前 24 小时内的不同国家的乘客人数呢?

      由题干可知,t ≤ 1e9,难不成要开个 1e9 大的数组,显然是不可行的,那该怎么办呢?

      看题干,保证所输入的 t 是递增的,而 n ≤ 1e5,所以可以将 affect[ i ] 中乘客 i 的影响范围由之前的时间区间变为船只编号,如何变呢?

      还是以样例为例;

       一共有 3 艘船,每艘船的到港时间分别为 1,2,10

       第一艘船的乘客可以影响的时间范围为[1,1+86400),也就是说,只要到港时间在[1,1+86400)范围内的船只,都可以影响到,

       而后两艘船的到港时间都在这个时间范围内,所以将 affect[1]=affect[2]=affect[4]=4,意思是第一艘船的第 1,2,4乘客可以影响到前三艘船。

       来到第二艘船,其乘客国籍为 2,3,但affect[2]=4 > 2,说明在这之前的 24 小时内,有船只载有 2 国家的乘客,所以当前船只的 2 乘客能

       影响的范围变为[affect[2],end),end 指的是到港时间 >= 2+86400 最近的一艘船编号,易得 end = 4。

       其余的船只同理。

       因为每艘船只的到港时间是递增的,所以每次查找可以使用二分。

       而第 i 艘船上的每个乘客的影响范围可以用树状数组或线段树来维护;

      而我选择了一个比较方便的差分数组,何为差分数组,详情请看 http://www.cnblogs.com/widsom/p/7750656.html

     


    Code

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define pb push_back
     4 #define lowbit(x) (x&(-x))
     5 #define mem(a,b) memset(a,b,sizeof a)
     6 const int maxn=1e5+50;
     7 
     8 int n;
     9 int arrive[maxn];
    10 int affect[maxn];
    11 vector<int >ship[maxn];
    12 int diff[maxn];
    13 void Solve()
    14 {
    15     mem(affect,0);
    16     mem(diff,0);
    17     for(int i=1;i <= n;++i)
    18     {
    19         //t : 到港时间 >= arrive[i]+86400 的最近的一艘船的编号
    20         int t=lower_bound(arrive+i,arrive+n+1,arrive[i]+86400)-arrive;
    21         for(int j=0;j < ship[i].size();++j)
    22         {
    23             int native=ship[i][j];
    24             if(affect[native] < i)//判断一下affect[native]影响的范围是否包含当前船只 i
    25                 affect[native]=i;//如果不包含,则当前乘客的影响范围从当前船只开始
    26             diff[affect[native]]++;//当前乘客的影响范围为 [affect[native],t)
    27             diff[t]--;
    28             affect[native]=t;//更新affect[native]
    29         }
    30     }
    31     for(int i=1;i <= n;++i)
    32     {
    33         diff[i] += diff[i-1];//一遍前缀和为元素本身,也就是以当前船只为终了时间的前24小时内的来自不同国家的个数
    34         printf("%d
    ",diff[i]);
    35     }
    36 }
    37 int main()
    38 {
    39     scanf("%d",&n);
    40     for(int i=1;i <= n;++i)
    41     {
    42         int t,k;
    43         scanf("%d%d",&t,&k);
    44         arrive[i]=t;
    45         for(int j=1;j <= k;++j)
    46         {
    47             int native;
    48             scanf("%d",&native);
    49             ship[i].pb(native);
    50         }
    51         sort(ship[i].begin(),ship[i].end());
    52         ship[i].erase(unique(ship[i].begin(),ship[i].end()),ship[i].end());
    53     }
    54     Solve();
    55 }
    56 /**
    57 5
    58 1 4 4 1 2 2
    59 2 2 2 3
    60 10 1 3
    61 100000 5 1 2 3 4 5
    62 100001 5 1 2 3 4 6
    63 **/
    View Code
  • 相关阅读:
    【转】五笔字根图
    数据集ds 转化为json
    js 计算 往前(后)几天(月、年)
    js 每秒刷新系统时间,可停止
    如何获取枚举字符串,值及遍历枚举
    js 正则判断值
    C#将时间格式 yyyymmdd hh:mm:ss转换为yyyyMMddHHmmss
    【转】什么是程序集?
    C# 两个日期相减得到月数和天数和时and计算 日期减去月之后的日期
    js判断一个下拉框的选中值是否改变
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/9859006.html
Copyright © 2011-2022 走看看