• [loj6039]「雅礼集训 2017 Day5」珠宝 dp+决策单调性+分治


    https://loj.ac/problem/6039

    我们设dp[i][j]表示考虑所有价值小于等于i的物品,带了j块钱的最大吸引力。

    对于ci相同的物品,我们一定是从大到小选k个物品,又发现最大的k个的价值在k变大的时候增长率是单调减的。

    同时对于同样的ci,被转移和转移到的状态mod ci同余。

    这些dp值也具有单调性,因此这个dp具有决策单调性。

    我们用分治优化转移。负责度O(c*k*logk)

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdlib>
     4 #include<cstdio>
     5 #include<cmath>
     6 #include<algorithm>
     7 #include<vector>
     8 #define maxn 305
     9 #define maxk 50005
    10 #define ll long long
    11 using namespace std;
    12 inline int read() {
    13     int x=0,f=1;char ch=getchar();
    14     for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
    15     for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    16     return x*f;
    17 }
    18 ll n,k,sz[maxn],pre=0,now=1;
    19 ll dp[2][maxk],g[2][maxk];
    20 vector<ll> q[maxn];
    21 bool cmp(ll a,ll b) {return a>b;}
    22 void solve(int l,int r,int ql,int qr,int x,int SZ) {
    23     if(l>r||ql>qr) return;
    24     int mid=ql+qr>>1,minmid=-1;ll val=0;
    25     for(int i=max(l,mid-SZ);i<mid&&i<=r;i++) {
    26         if(minmid==-1||g[0][i]+q[x][mid-i-1]>val) {
    27             val=g[0][i]+q[x][mid-i-1];minmid=i;
    28         }
    29     }
    30     g[1][mid]=val;
    31 //    if(minmid==-1) minmid=l;
    32     solve(l,minmid,ql,mid-1,x,SZ);solve(minmid,r,mid+1,qr,x,SZ);
    33 }
    34 int main() {
    35     n=read(),k=read();
    36     for(int i=1;i<=n;i++) {
    37         int x=read(),y=read();
    38         q[x].push_back(y);sz[x]++;
    39     }
    40     for(int i=1;i<=300;i++) {
    41         if(!sz[i]) continue;
    42         sort(q[i].begin(),q[i].end(),cmp);
    43         for(int j=1;j<sz[i];j++) q[i][j]+=q[i][j-1];
    44         for(int j=0;j<i;j++) {
    45             int p=j,bk=0;
    46             for(;p<=k;p+=i,bk++) g[0][bk]=dp[pre][p];
    47             solve(0,bk-1,0,bk-1,i,sz[i]);
    48             p=j,bk=0;
    49             for(;p<=k;p+=i,bk++) dp[now][p]=max(g[0][bk],g[1][bk]);
    50         }
    51         swap(now,pre);
    52     }
    53     for(int i=1;i<=k;i++) printf("%lld ",dp[pre][i]);
    54 }
    View Code
  • 相关阅读:
    51nod1363-最小公倍数之和
    [模板] 数论题的一些经验
    WC2019游记 && 课件
    (伪)WC2019题解
    [模板] 后缀自动机&&后缀树
    [模板] 二分图博弈 && BZOJ2463:[中山市选2009]谁能赢呢?
    界面修改日志
    [模板] dp套dp && bzoj5336: [TJOI2018]party
    BZOJ1025:[SCOI2009]游戏
    [模板] BSGS/扩展BSGS
  • 原文地址:https://www.cnblogs.com/wls001/p/10184957.html
Copyright © 2020-2023  润新知