• [cf1515I]Phoenix and Diamonds


    将$n$类物品按照价值为第一关键字(从大到小)、质量为第二关键字(从小到大)排序,此时贪心策略即依次贪心选(排序后)第$i$类的物品(其中$i$从1到$n$)

    为了方便,排序后第$i$类物品质量、价值和个数仍用$w_{i},v_{i}$和$a_{i}$描述(即默认初始排序)

    $forall 0le kle 30$,维护一棵线段树,其中区间$[l,r]$维护:

    1.$sum_{lle ile r,w_{i}<2^{k}}a_{i}w_{i}$和$sum_{lle ile r,w_{i}<2^{k}}a_{i}v_{i}$(特别的,若$w_{i}ge 2^{k}$则$a_{i}$强制为0)

    2.$min_{lle jle r,2^{k}le w_{j}<w^{k+1},a_{j}ge 1}(sum_{lle i<j,w_{i}<2^{k}}a_{i}w_{i}+w_{j})$(特别的,若不存在$j$则强制为$infty$)

    修改操作会影响$o(log n)$棵线段树,单次修改复杂度即$o(log^{2}n)$

    设已经贪心到第$l$类物品(第$l$类还未贪心),箱子剩余的容纳质量为$c$,取最大的$0le kle 30$满足$cge 2^{k}$

    考虑找到最小的$r$,满足$min_{lle jle r,2^{k}le w_{j}<w^{k+1},a_{j}ge 1}(sum_{lle i<j,w_{i}<2^{k}}a_{i}w_{i}+w_{j})le c$,通过在$k$对应的线段树上二分即可做到$o(log n)$的复杂度

    若存在这样的$r$,此时即将$c$减去$sum_{lle i<r,w_{i}<2^{k}}a_{i}w_{i}+w_{r}$,答案增加$sum_{lle i<r,w_{i}<2^{k}}a_{i}v_{i}+v_{r}$

    若不存在这样的$r$,再找到最小的$r$,满足$sum_{lle ile r,w_{i}<2^{k}}a_{i}w_{i}>c$,同样在线段树上二分实现

    此时即将$c$减去$sum_{lle i<r,w_{i}<2^{k}}a_{i}w_{i}$,答案增加$sum_{lle i<r,w_{i}<2^{k}}a_{i}v_{i}$,再手动贪心第$r$类物品(特别的,若$r>n$则跳过这一步)

    最终,再把$l$变为$r+1$即可

    关于正确性,分析如下——

    对于第一种情况,即选择了$[l,r)$中所有$w_{i}<2^{k}$的物品,也即求证若$r'$满足$lle r'<r$且$w_{r'}ge 2^{k}$,$w_{r'}$必然不会被选择,对$w_{r'}$的情况分类讨论:

    1.$w_{r'}<2^{k+1}$,此时如果会被选择,显然将$r$变为$r'$更优

    2.$w_{r'}ge 2^{k+1}$,若$c=30$显然不存在此类物品,否则必然有$c<2^{k+1}$,也不能被选择

    而对于$w_{r}$,上述式子的最小值必然在$j=r$时取到(否则令$r$为取到最小值的$j$更优),即$w_{r}ge 2^{k}$,因此$w_{r}$至多选择一个,且可以被选择,即选择一个即可

    对于第二种情况,由于不存在$r$,也即一定不能选择$w_{i}ge 2^{k}$的物品,因此仅考虑$w_{i}<2^{k}$的物品即可

    关于最后的手动贪心,若$w_{r}ge 2^{k}$显然将$r$变为$r+1$更优,因此必然有$w_{r}<2^{k}$,且一定不能全部选择(同样将$r$变为$r+1$更优)

    关于时间复杂度,分析如下——

    事实上,不论哪一种情况,最终都会有$c<2^{k}$或$l>n$

    第一种情况,由于选择了$w_{r}ge 2^{k}$的物品,显然$c<2^{k}$

    第二种情况,由于最终手动贪心第$r$类物品,根据前面的分析$w_{r}<2^{k}$且不能全部选择,那么最终若$cge 2^{k}$则还可以再选一个$w_{r}$的物品(特别的,若$r>n$即$l>n$)

    由此,上述过程至多执行$o(log n)$次,单次询问复杂度即$o(log^{2}n)$

    综上,总时间复杂度为$o(nlog^{2}n)$,可以通过

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define N 200005
      4 #define ll long long
      5 #define L (k<<1)
      6 #define R (L+1)
      7 #define mid (l+r>>1)
      8 struct Thing{
      9     int a,w,v,id;
     10     bool operator < (const Thing &k)const{
     11         return ((v>k.v)||(v==k.v)&&(w<k.w));
     12     }
     13 }a[N];
     14 struct Data{
     15     ll w,v,mn;
     16 }o,f[31][N<<2];
     17 int n,q,p,x,y,id[N];
     18 ll z;
     19 void get(int k,int x){
     20     for(int i=0;i<=30;i++){
     21         f[i][k]=o;
     22         if (a[x].w<(1<<i)){
     23             f[i][k].w=1LL*a[x].a*a[x].w;
     24             f[i][k].v=1LL*a[x].a*a[x].v;
     25         }
     26         else{
     27             if ((i<30)&&(a[x].w<(1<<i+1))&&(a[x].a>=1))f[i][k].mn=a[x].w;
     28         }
     29     }
     30 }
     31 Data merge(Data x,Data y){
     32     return Data{x.w+y.w,x.v+y.v,min(x.mn,y.mn+x.w)};
     33 }
     34 void up(int k){
     35     for(int i=0;i<=30;i++)f[i][k]=merge(f[i][L],f[i][R]);
     36 }
     37 void build(int k,int l,int r){
     38     if (l==r){
     39         get(k,l);
     40         return;
     41     }
     42     build(L,l,mid);
     43     build(R,mid+1,r);
     44     up(k);
     45 }
     46 void update(int k,int l,int r,int x){
     47     if (l==r){
     48         get(k,x);
     49         return;
     50     }
     51     if (x<=mid)update(L,l,mid,x);
     52     else update(R,mid+1,r,x);
     53     up(k);
     54 }
     55 Data query(int p,int k,int l,int r,int x,int y){
     56     if ((l>y)||(x>r))return o;
     57     if ((x<=l)&&(r<=y))return f[p][k];
     58     return merge(query(p,L,l,mid,x,y),query(p,R,mid+1,r,x,y));
     59 }
     60 int find1(int p,int k,int l,int r,int x,ll &y){//找到大于等于x的位置中第一个mn<=y的位置 
     61     if (r<x)return n+1;
     62     if ((l>=x)&&(f[p][k].mn>y)){
     63         y-=f[p][k].w;
     64         return n+1;
     65     }
     66     if (l==r)return l;
     67     int ans=find1(p,L,l,mid,x,y);
     68     if (ans<=n)return ans;
     69     return find1(p,R,mid+1,r,x,y);
     70 }
     71 int find2(int p,int k,int l,int r,int x,ll &y){//找到大于等于x的位置中第一个w>y的位置 
     72     if (r<x)return n+1;
     73     if ((l>=x)&&(f[p][k].w<=y)){
     74         y-=f[p][k].w;
     75         return n+1;
     76     }
     77     if (l==r)return l;
     78     int ans=find2(p,L,l,mid,x,y);
     79     if (ans<=n)return ans;
     80     return find2(p,R,mid+1,r,x,y);
     81 }
     82 ll query(ll c){
     83     int pos=1;
     84     ll cc,ans=0;
     85     while ((pos<=n)&&(c)){
     86         int k=0,nex;
     87         for(int i=0;i<=30;i++)
     88             if ((1<<i)<=c)k=i;
     89         nex=find1(k,1,1,n,pos,cc=c);
     90         if (nex<=n){
     91             Data o=query(k,1,1,n,pos,nex-1);
     92             c-=o.w+a[nex].w,ans+=o.v+a[nex].v;
     93         }
     94         else{
     95             nex=find2(k,1,1,n,pos,cc=c);
     96             Data o=query(k,1,1,n,pos,nex-1);
     97             c-=o.w,ans+=o.v;
     98             if (nex<=n){
     99                 ll s=c/a[nex].w;
    100                 c-=s*a[nex].w,ans+=s*a[nex].v;
    101             }
    102         }
    103         pos=nex+1;
    104     }
    105     return ans;
    106 }
    107 int main(){
    108     o.mn=2e18;
    109     scanf("%d%d",&n,&q);
    110     for(int i=1;i<=n;i++){
    111         scanf("%d%d%d",&a[i].a,&a[i].w,&a[i].v);
    112         a[i].id=i;
    113     }
    114     sort(a+1,a+n+1);
    115     for(int i=1;i<=n;i++)id[a[i].id]=i;
    116     build(1,1,n);
    117     for(int i=1;i<=q;i++){
    118         scanf("%d",&p);
    119         if (p==1){
    120             scanf("%d%d",&x,&y);
    121             y=id[y];
    122             a[y].a+=x;
    123             update(1,1,n,y);
    124         }
    125         if (p==2){
    126             scanf("%d%d",&x,&y);
    127             y=id[y];
    128             a[y].a-=x;
    129             update(1,1,n,y);
    130         }
    131         if (p==3){
    132             scanf("%lld",&z);
    133             printf("%lld
    ",query(z));
    134         }
    135     }
    136 }
    View Code
  • 相关阅读:
    charles使用
    断言
    JDBC Request
    HTTP请求建立一个测试计划
    利用badboy进行脚本录制
    接口测试用例
    Monkey常用命令
    charles安装与使用
    celery配置与基本使用
    图片验证码接口
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14924517.html
Copyright © 2020-2023  润新知