bzoj 1110: [POI2007]砝码Odw 贪心

第一次见到这个模型.   

首先,不难得出砝码的种类不会超过 $log(10^9)$ 个,然后就不会分析了qaq...  

那么,就说明一共只有 $30$ 多个本质不同的砝码. 

考虑对每个背包进行状态的压缩:写成若干个砝码大小乘积的形式. 

即 $v[i]=w[i]*a+w[i+1]*b+....$   

然后,将所有背包的系数加和 (有点类似于不进位的进制)

因为呢,你发现两个是不能拼成更大的背包的,所以只能在原有的位置上累加. 

根据贪心,我们一定优先装更小的物品. 

如果这一位有值,直接在这一位上拿一个即可,否则就要从高位借一个,然后给之间每一位的系数都累加一下.   

code: 

#include <bits/stdc++.h> 
using namespace std; 
void setIO(string s) 
{
    string in=s+".in"; 
    freopen(in.c_str(),"r",stdin); 
}
int n,m,len,ans;     
int bas[52],w[100010],v[100010],c[52];    
int main() 
{
    // setIO("input"); 
    int i,j; 
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;++i)      scanf("%d",&w[i]); 
    for(i=1;i<=m;++i)      scanf("%d",&v[i]);
    sort(v+1,v+1+m); 
    for(i=1;i<=m;++i) 
    {
        if(v[i]>bas[len]) bas[++len]=v[i];   
        v[i]=len;   
    }
    for(i=1;i<=n;++i)    for(j=len;j;--j) c[j]+=w[i]/bas[j],w[i]%=bas[j]; 
    for(i=1;i<=m;++i) 
    {
        if(c[v[i]]) c[v[i]]--,ans++;  
        else 
        {
            for(j=v[i];j<=len;++j) 
            {
                if(c[j]) 
                {
                    --c[j];  
                    break;  
                }
                else 
                {
                    c[j]=bas[j+1]/bas[j]-1;  
                }
            }
            if(j>len)      break; 
            else     ++ans;   
        }
    }
    printf("%d\n",ans);  
    return 0; 
}

  

posted @ 2019-10-29 22:18  EM-LGH  阅读(125)  评论(0编辑  收藏  举报