[POI2007]砝码Odw

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

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

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

Sample Input
2 4
13 9
4 12 2 4

Sample Output
3

本题砝码的特性决定了我们可以用一个特殊的方法

将所有容量转变为砝码的进制表示,例如容量为45,当砝码有2,4,8,32时,他可以表示为\(1\times 32+1\times 8+1\times 4+0\times 2+1\),由于1我们用不上,那么从低到高位就表示成(0,1,1,1)。那么我们可以把所有的容量都表示成如此形式,并且对其进行不进位加法,如果说我们还有一个容器为(1,2,1,0),那么它们俩的总表达式为(1,3,2,1)

根据贪心的思想,显然我们放砝码的时候从小的放起是最优的。所以当我们就先使用小的容量,比如我们有一个2的时候,就将它扔进最小的容量里,表达式变成(0,3,2,1)。如果小容量还有剩余,但是已经没有小砝码的时候,我们就只能抛弃那些多出来的小容量;如果小容量不够的时候,我们就从他后一个容量借一个,比如现在如果8不够的话可以从32那里借4个8来用

但剩余容量不够再放的时候停止,此时放进去的砝码个数即为最优解

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
    int x=0,f=1;char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())    x=(x<<1)+(x<<3)+ch-'0';
    return x*f;
}
inline void print(int x){
    if (x>=10)     print(x/10);
    putchar(x%10+'0');
}
const int N=1e5,M=50;
int A[N+10],B[N+10];
int C[M+10],cnt[M+10];
int n,m,tot;
bool check(int x){
    for (int i=x+1;i<=tot;i++)
        if (cnt[i]){
            cnt[x]+=C[i]/C[x];
            cnt[i]--;
            return 1;
        }
    return 0;
}
int main(){
    n=read(),m=read();
    for (int i=1;i<=n;i++)  A[i]=read();
    for (int i=1;i<=m;i++)  B[i]=read();
    sort(B+1,B+1+m);
    for (int i=1;i<=m;i++)  if (B[i]!=B[i-1])   C[++tot]=B[i];
    for (int i=1;i<=n;i++)
        for (int j=tot;j;j--)
            while (C[j]<=A[i]){
                A[i]-=C[j];
                cnt[j]++;
            }
    int Now=1;
    for (int i=1;i<=m;i++){
        while (B[i]>C[Now]) Now++;
        if (cnt[Now])   cnt[Now]--;
        else    if (check(Now)) cnt[Now]--;
        else{
            printf("%d\n",i-1);
            return 0;
        }
    }
    printf("%d\n",m);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Wolfycz/p/8905821.html