BZOJ-1190: [HNOI2007]梦幻岛宝珠

[文章目录]

Description

给你N颗宝石,每颗宝石都有重量和价值。要你从这些宝石中选取一些宝石,保证总重量不超过W,且总价值最大为,并输出最大的总价值。数据范围:N<=100;W<=2^30,并且保证每颗宝石的重量符合a*2^b(a<=10;b<=30)

一个数据范围超大的背包???
GXZ讲这道提的时候说应该发现一些特点。显然是重量。假设对于不同的b分别跑背包的话,剩余体积不超过n*a。那么问题就在于处理不同的b之间的问题上了。当一位剩b体积的收益,可以转化为下一位剩b*2加上总体积在次微商的只。那么就可以从高位向低位递推了。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,m,ans,f[1100],g[1100];
struct node
{
    int a,b,w;
}a[110];
bool cmp(node x,node y){return x.b>y.b;}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        if(n==-1) return 0;
        int i,j,k,tmp;
        for(i=1;i<=n;++i)
        {
            scanf("%d%d",&a[i].a,&a[i].w);
            for(a[i].b=0;a[i].b<=30&&!((a[i].a>>a[i].b)&1);a[i].b++);
            a[i].a>>=a[i].b;
        }
        sort(a+1,a+n+1,cmp);
        memset(f,0xc0,sizeof f); f[0]=0;
        for(i=30,j=1;~i;--i)
        {
            memset(g,0xc0,sizeof g);
            for(k=0;k<=1000;++k)
                tmp=min(1000,(k<<1)+((m>>i)&1)),
                g[tmp]=max(g[tmp],f[k]);
            swap(g,f);
            for(;j<=n&&a[j].b==i;++j)
                for(k=a[j].a;k<=1000;++k)
                    f[k-a[j].a]=max(f[k-a[j].a],f[k]+a[j].w);
        }
        for(ans=i=0;i<=1000;++i) ans=max(ans,f[i]);
        printf("%d\n",ans);
    }
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注