Allowance

Posted a1b3c7d9

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Allowance相关的知识,希望对你有一定的参考价值。

Allowance

有n种数字,第i种数字值为\(v_i\),有\(b_i\)个,保证随i的增大而增大,且对于任意i有\(a_i-1|a_i\)(显然,\(i\in(1,n]\)),现求将它们划分成最多的组数,并且保证每一组的数字的和大于等于c;\(n\leq 20,c,v\leq 10^8\)

显然要分的组数最多,要能够做到拿出一组中的一个最小的数字,让其不满足条件,即填到尽量满,显然每一组都要尽可能做到。

于是我们从大往小填一组,如果当前枚举的数字为i,如果不选i,而转而选比i小的数字,容易发现因为整除的性质,那些比i小的数字必然会凑成i,更进一步,也就是选i的决策包含了不选i的决策,于是i一定要选。

因此我们就得到了一个凑的满满的组,显然再向其中填入一个数字,一定会超过c,容易知道,要让组数最大,显然需要填入一个当前能填的最小数字,这样满足了一组的和尽可能小,所以最优。

于是我们得到一个做法,从大到小枚举数字,填到不能填为止(这里应该用同余的知识优化,而不是一个一个选),再从小到大选择一个数字,如果总和大于等于c,则++ans。

考虑进一步优化,我们显然一个做法下来,得到了一个组的分配方法,于是我们可以copy,这样就可以做到很快了。

参考代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define il inline
#define ri register
#define Size 25
#define intmax 0x7fffffff
using namespace std;
struct coin
    int v,b;
    il bool operator<(const coin&a)const
        return v<a.v;
    
co[Size];
int ct,a[Size];
int main()
    int n,c,ans(0);
    scanf("%d%d",&n,&c);
    for(int i(1),v,b;i<=n;++i)
        scanf("%d%d",&v,&b);
        if(v>=c)ans+=b;
        else co[++ct]=v,b;
    sort(co+1,co+ct+1);
    while(true)int X(c);
        for(int i(ct),j;i;--i)
            j=min(X/co[i].v,co[i].b);
            a[i]=j,X-=j*co[i].v,co[i].b-=j;
        
        if(X)for(int i(1);i<=ct;++i)
                 if(co[i].b)++a[i],--co[i].b,X-=co[i].v;break;
        if(X>0)break;++ans;int opt(intmax);
        for(int i(1);i<=ct;++i)
            if(a[i])opt=min(opt,co[i].b/a[i]);ans+=opt;
        for(int i(1);i<=ct;++i)co[i].b-=opt*a[i];
    printf("%d",ans);
    return 0;

以上是关于Allowance的主要内容,如果未能解决你的问题,请参考以下文章