LOJ6039「ヤリトレーニング2017 Day5「ジュエリー

タイトル

お知らせ\(C_I \当量300 \)我々は明らかに使用することができます(C_I \)\彼の事を実行するために

自然のアイデアは、私たちに基づいています\(C_I \)のグループ化、我々は問題に変換しているので、各グループ内のアイテムのボリュームは、複数の物品に、降順ので、値に応じて、同じですパケットナップザック問題

我々はそのようなA持っているので\(DPを\)、\ (dp_ {I、J} = \最大dp_ {I-1、JK \タイムズI} + W_ {I、K} \)、\ (W_ {I、 kは} \)を表し\(I \)前群\(K \)物品の値が、複雑さは依然として高すぎるパケット・バックパック

、見つけるのは難しいことではありません\(J \)\(JI \倍のK \)である(\ MOD \ I \)\私達はに従って同じグループのために作ることができますので、感覚に等しい(\ MOD \ I \)\値分類

また、で見つけることができます\(DP \)プレゼンス決定単調、もし\(JK \回I \)より\(JP \回I(P > K)\) で\(J \) より好ましくは、大きいため\(Jは\)である\(JK \回I \) またはそれよりも\(JP \タイムズI \)ので、\({I、K} W_ \) 、すべての後に正の差分であるJK(\ \回私は\)よりも速く成長している(JP \回I \)\私たちはパーティションを指示することができますので、

複雑さがある(O(MC \ログメートル\ \)) コード

#include<bits/stdc++.h>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
inline int read() {
    char c=getchar();int x=0;while(c<'0'||c>'9')c=getchar();
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
int n,m,nw,T;
std::vector<LL> w[305];
LL dp[50005],g[50005],f[50005];
inline int cmp(LL A,LL B) {return A>B;}
void solve(int l,int r,int x,int y) {
    if(l>r) return;int mid=l+r>>1;
    f[mid]=g[mid];int id=mid;
    for(re int i=x;i<=y&&i<mid;++i) {
        if(mid-i>w[nw].size()) continue;
        LL k=g[i]+w[nw][mid-i-1];
        if(k>f[mid]) f[mid]=k,id=i;
    }
    if(l==r)return;
    solve(l,mid-1,x,id);solve(mid+1,r,id,y);
}
int main() {
    n=read(),m=read();
    for(re int c,v,i=1;i<=n;i++)c=read(),v=read(),w[c].push_back((long long)v),T=max(c,T);
    for(re int i=1;i<=T;i++) {
        if(!w[i].size()) continue;
        std::sort(w[i].begin(),w[i].end(),cmp);
        for(re int j=1;j<w[i].size();++j) w[i][j]+=w[i][j-1];
    }
    for(re int i=T;i;i--) {
        if(!w[i].size())continue;nw=i;
        for(re int tot=0,j=0;j<i;j++,tot=0) {
            for(re int k=j;k<=m;k+=i) g[++tot]=dp[k];
            solve(1,tot,1,tot);
            for(re int h=1,k=j;k<=m;k+=i,++h) dp[k]=f[h];
        }
        for(re int j=1;j<=m;j++)dp[j]=max(dp[j],dp[j-1]);
    }
    for(re int i=1;i<=m;i++) printf("%lld ",dp[i]);
    return 0;
}

おすすめ

転載: www.cnblogs.com/asuldb/p/12155151.html