• tyvj4751 NOIP春季系列课程 H's Problem (树状数组)


    -H's Problem-

    描述

      小H是一个喜欢逛街的女孩子,但是由于上了大学,DDL越来越多了,她不能一直都处于逛街的状态。为了让自己能够更加沉迷于学习,她规定一次逛街只逛T个单位的时间。

      小H从1号店出发,从1号店走到第i号店需要花费ai的时间,这些店形成了一条直线,也就是说小H从第i号店走到第i+1号店需要花费的时间为a{i+1}-ai。若小H选择了第i号店并且进去逛,则会消耗bi的时间。对于第i家店,小H都对它有自己的看法。具体地,可以用ci来表示小H是否喜欢这家店。如果ci=1,则表示小H喜欢i号店,否则若ci=0,则表示小H不喜欢这家店。

      小H想尽可能逛更多的店,但是她也有属于自己的目标,也就是说逛至少k家喜欢的店,在这个基础上,能逛的店越多越好。

      小H现在想知道自己最多能逛多少店,当然若小H无论如何也逛不到k家喜欢的店,那么你输出-1就行了。

    输入格式

    第一行3个数n,T,k。

             接下来一行n个数表示ai。

             接下来一行n个数表示bi。

             接下来一行n个数表示ci。

    输出格式

    输出一个数表示答案。

     

    数据结构;

    先分析下题意,我们要求的是在$1-n$中选择尽量多的店去逛,同时至少逛$k$家我们喜欢的店;

    因为到每家店所需时间不同,我们走的越远,剩余逛店时间就越少,但可选择的店会增多,所以答案上不具备单调性,只能枚举每一个点作为终点,然后分别求答案数;

    对于任意一点$i$作为终点求答案数,实际就是在$1-i$中选择尽量多的点,即求一个动态升序数组的前$x$项,使它们的和$<=T-a[i]$;

    我们注意到元素的插入顺序和元素大小都是已知的,因此可以通过离散化+排序,预处理出所有元素在数组中应在的位置,构建一个静态数组,将原本需要动态维护的数组离线处理,把元素按顺序放进它应在的位置;

    因为数组中元素有序,所以我们求前缀和即可;

    对一个数组进行单点修改和求前缀和,很明显可以使用树状数组(当然线段树也可);

    树状数组中下标代表元素大小(离散化后),每个节点存储元素个数及元素权值和(离散化前);

    前缀和是连续的,因此可以对下标进行二分查找;

    最后对于必须逛够$k$家喜欢的店的问题,因为只需选择$1-i$中前$k$家耗时最少的店,我们可以维护一个大根堆,存储前$k$小的$k$个元素,从堆中踢出或未进堆元素则存入树状数组;

    复杂度$O(n*logn*logn)$;

    (实际上还可以用平衡树/线段树做,复杂度$O(n*logn)$

    AC GET☆DAZE

     

    ↓代码(只有70分orz

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cmath>
      5 #include<algorithm>
      6 #include<vector>
      7 #define ll long long
      8 #define MAX_L 0x7fffffff7fffffff
      9 using namespace std;
     10 struct mk
     11 {
     12     ll c,r;
     13 };
     14 struct poi
     15 {
     16     ll n,s;
     17 };
     18 mk shop[100039];
     19 poi tree[100039]={0};
     20 ll rou[100039],tim[100039],ord[100039],hea[100039]={0},size=0,n,sum,calcs;
     21 bool kn[100039]={0};
     22 bool cmp(mk a,mk b)
     23 {
     24     return a.c<b.c;
     25 }
     26 void ueni()
     27 {
     28     ll a=size,key=hea[size];
     29     while(1)
     30     {
     31         if(tim[hea[a/2]]<tim[key])
     32         {
     33             hea[a]=hea[a/2];
     34             a/=2;
     35         }
     36         else
     37         {
     38             hea[a]=key;
     39             return;
     40         }
     41     }
     42 }
     43 void sitani()
     44 {
     45     ll a=1,key=hea[1],ne;
     46     while(1)
     47     {
     48         ne=a*2;
     49         if(tim[hea[a*2]]<tim[hea[a*2+1]])
     50         {
     51             ne++;
     52         }
     53         if(a*2>size)
     54         {
     55             hea[a]=key;
     56             return;
     57         }
     58         if(tim[hea[ne]]>tim[key])
     59         {
     60             hea[a]=hea[ne];
     61             a=ne;
     62         }
     63         else
     64         {
     65             hea[a]=key;
     66             return;
     67         }
     68     }
     69 }
     70 ll lowbit(ll k)
     71 {
     72     return -k&k;
     73 }
     74 void maketree(ll x)
     75 {
     76     ll a=ord[x];
     77     while(a<=n)
     78     {
     79         tree[a].n+=tim[x];
     80         tree[a].s++;
     81         a+=lowbit(a);
     82     }
     83     return;
     84 }
     85 ll calctree(ll x)
     86 {
     87     ll calcn=0,a=x;
     88     calcs=0;
     89     while(a)
     90     {
     91         calcn+=tree[a].n;
     92         calcs+=tree[a].s;
     93         a-=lowbit(a);
     94     }
     95     return calcn;
     96 }
     97 int main()
     98 {
     99     mk stp;
    100     ll T,k,t,l,r,m,ans=-1,a,b,c;
    101     scanf("%lld%lld%lld",&n,&T,&k);
    102     for(a=1;a<=n;a++)
    103     {
    104         scanf("%lld",&rou[a]);
    105     }
    106     for(a=1;a<=n;a++)
    107     {
    108         scanf("%lld",&tim[a]);
    109         stp.c=tim[a];
    110         stp.r=a;
    111         shop[a]=stp;
    112     }
    113     for(a=1;a<=n;a++)
    114     {
    115         scanf("%lld",&kn[a]);
    116     }
    117     sort(shop+1,shop+n+1,cmp);
    118     for(a=1;a<=n;a++)
    119     {
    120         ord[shop[a].r]=a;
    121     }
    122     tim[0]=MAX_L;
    123     for(a=1;a<=n;a++)
    124     {
    125         if(kn[a])
    126         {
    127             if(size<k)
    128             {
    129                 T-=tim[a];
    130                 hea[++size]=a;
    131                 ueni();
    132             }
    133             else
    134             {
    135                 if(hea[1]!=0 && tim[a]<tim[hea[1]])
    136                 {
    137                     T-=tim[a];
    138                     T+=tim[hea[1]];
    139                     maketree(hea[1]);
    140                     hea[1]=a;
    141                     sitani();
    142                 }
    143                 else
    144                 {
    145                     maketree(a);
    146                 }
    147             }
    148         }
    149         else
    150         {
    151             maketree(a);
    152         }
    153         t=T-rou[a];
    154         if(size==k && t>=0)
    155         {
    156             l=1,r=n;
    157             while(l+39<r)
    158             {
    159                 m=(l+r)>>1;
    160                 if(calctree(m)<=t)
    161                 {
    162                     l=m;
    163                 }
    164                 else
    165                 {
    166                     r=m;
    167                 }
    168             }
    169             while(calctree(l)<=t && l<=n)
    170             {
    171                 l++;
    172                 sum=calcs;
    173             }
    174             ans=max(ans,sum+k);
    175         }
    176     }
    177     printf("%lld",ans);
    178     return 0;
    179 }
    tyvj4751
    散りぬべき 時知りてこそ 世の中の 花も花なれ 人も人なれ
  • 相关阅读:
    抽象类
    《大道至简》第七八章读后感
    使用try输出成绩
    《大道至简》第六章读后感
    课后作业2015.11.9
    《大道至简》第五章读后感
    课后作业2015.11.1
    动手动脑20151024
    字串加密
    《大道至简》第四章读后感
  • 原文地址:https://www.cnblogs.com/Sinogi/p/7197283.html
Copyright © 2020-2023  润新知