• 珠宝 jewelry 省选模拟


    n种珠宝。每种各1个。有价格ci元,美度vi。  要求分别输出1元到m元 可买的最大优美度。

    整数 :0<n<=10000000, 0<ci<=300,0<=vi<=10^9, 0<m<=50000; 

    之前 系统的看过有关背包的题目。。然而这个做法还没见过。

    首先复杂度是 300*m*log(m)+n

    对1~300的每个价格 x, 按v从大到小排序,形成一个b数组。记录了价格为x的vi的前缀和(这里记为bj,   b[j]=b[j-1]+vi(当然。若j*x>m时 不用再继续记录。)

      因为固定了当前只取价格为x的珍宝,所以,设f[i]为i元能买的最大价值  f[i]只能由f[i-t*u](t为自然数)更新而来。。 而b数组是上凸壳(①b是不减的,②因为对相同的价格,按vi从大到小排序。所以b的斜率是不增的。)

     那么就可以用栈来做了:  设a[]为上一种价格x'计算完后 的f[],然后用a[]和b[]来更新f[]  ,那么f[i]=max(a[i-k*x]+b[i]), 换句话说,可以发现 每个a[i]可以在一段l~r上 作为max,且不会有另外的位置它会作max,同时i越大,对应的l,r也大。

       可以设 i%x=u  那么枚举u=0~x-1, 然后O(m/x)的扫一遍——for(i=u;i<=m;i+=x) , 用栈求出 每个a[i] 的l~r, 然后更新f[]。

    细节多*意识模糊=一个晚上的颓废。。。。 上代码

     1 #include <cmath>
     2 #include <cstdio>
     3 #include <cctype>
     4 #include <algorithm>
     5 #define LL long long
     6 using namespace std;
     7 template<class T> inline void gn(T &x) {
     8     char c; while(!isdigit(c=getchar())); x=c-'0';
     9     while(isdigit(c=getchar())) x=x*10+c-'0';
    10 }
    11 struct bla{
    12     int c; LL v;
    13 }o[1000005];
    14 int l,r,u,n,m,k,t,x,y,z,p,q,d[1000005],e[1000005];
    15 LL b[1000005],a[53005],f[53005];
    16 inline bool cmp(bla a,bla b){if (a.c!=b.c) return a.c<b.c; return a.v>b.v;}
    17 inline int get(int p,int q){
    18     int L=(p-u)/x,R=(q-u)/x,l=R-1,r=(m-u)/x,j;
    19     while (l<r){
    20         j=l+r+1>>1;
    21         if(a[p]+b[j-L]>=a[q]+b[j-R]) l=j; else r=j-1;
    22     }
    23     return u+l*x;
    24 }
    25 int main(){
    26     freopen("jewelry.in","r",stdin);
    27     freopen("jewelry.out","w",stdout);
    28     gn(n); gn(m);
    29     for (int i=1;i<=n;++i) gn(o[i].c),gn(o[i].v);
    30     sort(o+1,o+n+1,cmp);
    31     for (int I=1,J;I<=n;I=J){
    32         x=o[I].c;
    33         for (int i=1;i<=k;++i) b[i]=0; k=0;
    34         for (J=I;o[J].c==o[I].c;++J)
    35             if (k*x+x<=m) b[++k]=b[k-1]+o[J].v;
    36         if (k*x>m) --k;
    37         for (int i=0;i<=m;++i) a[i]=f[i],f[i]=0;
    38         for (u=0;u<x;++u){
    39             t=0;
    40             for (int i=u;i<=m;i+=x){
    41                    while (t){
    42                     e[t]=get(d[t],i);
    43                     if (e[t]>e[t-1]) break;
    44                     --t;
    45                 } 
    46                 d[++t]=i;
    47             }
    48             e[t]=(m-u)/x*x+u;
    49             for (int i=1;i<=t;++i)
    50             for (int j=e[i];j>e[i-1];j-=x) f[j]=max(f[j],a[d[i]]+b[(j-d[i])/x]);
    51         }
    52     }
    53     for (int i=1;i<=m;++i){
    54         f[i]=max(f[i],f[i-1]);
    55         printf("%I64d ",f[i]);
    56     }
    57     return 0;
    58 }
    Sad
  • 相关阅读:
    keeprunning1的使用说明
    团队冲刺第十五天
    团队冲刺第十四天
    团队第一阶段冲刺评价
    团队第一阶段成果展示
    团队冲刺第十三天
    团队冲刺第十二天
    团队冲刺第十一天
    团队冲刺第十天
    团队冲刺第九天
  • 原文地址:https://www.cnblogs.com/cyz666/p/6561724.html
Copyright © 2020-2023  润新知