[BZOJ1110] [POI2007]砝码Odw

题目描述

Description

在byteotian公司搬家的时候,他们发现他们的大量的精密砝码的搬运是一件恼人的工作。公司有一些固定容
量的容器可以装这些砝码。他们想装尽量多的砝码以便搬运,并且丢弃剩下的砝码。每个容器可以装的砝码数量有
限制,但是他们能够装的总重量不能超过每个容器的限制。一个容器也可以不装任何东西。任何两个砝码都有一个
特征,他们的中总有一个的重量是另外一个的整数倍,当然他们也可能相等。

Input

第一行包含两个数n和m。表示容器的数量以及砝码的数量。(1<=n, m<=100000) 第二行包含n个整数wi,表示
每个容器能够装的最大质量。(1<=wi<=1000000000) 第三行包含m个整数mj,表示每个砝码的质量。(1<=mj<=10000
00000)

Output

仅包含一个数,为能够装进容器的最多的砝码数量。

Sample Input

2 4
13 9
4 12 2 4

Sample Output

3

题目分析

比较强的贪心
注意到< 总有一个的重量是另外一个的整数倍 >这个性质 我们把所有的a[]分解成b[]的倍数的形式 优先分解最大的b[]
贪心策略:能装小的肯定先装小的
那我们就从小到大枚举b[] 如果能装就装 不能装看看能不能从高位借位

#include <cstdio>
#include <cstring>
#include <set>
#include <map>
#include <vector>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;
int n,m,cnt,dx=1;
int a[100100],b[100100],c[200],d[100100];
int can()
{
    for(int i=dx+1;dx<=cnt;dx++)
        if(d[i]>0)
        {
            d[i]--,d[dx]+=c[i]/c[dx];
            return 1;
        }
    return 0;
}
int main()
{   
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=m;i++) scanf("%d",&b[i]);
    sort(b+1,b+m+1);
    for(int i=1;i<=m;i++) if(b[i]!=b[i-1]) c[++cnt]=b[i];
    for(int i=cnt;i>=1;i--)
        for(int j=1;j<=n;j++) d[i]+=a[j]/c[i],a[j]%=c[i];
    for(int i=1;i<=m;i++)
    {
        while(c[dx]<b[i]) dx++;
        if(d[dx]) d[dx]--;
        else if(can()) d[dx]--;
        else
        {
            printf("%d",i-1);
            return 0;
        }
    }
    printf("%d",m);
    return 0;
}


发表评论

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