【2018年东北赛】UPC-7226 Memory Banks(模拟存储)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kuronekonano/article/details/82820495

题目描述
We have purchased 60 different types of memory banks, typed as 0 to 59, A bank of type i has 2i memory capacity. We have Xi memory banks of type i.
We also have n workstations numbered from 1 to n. The ith workstation needs exactly (no more and no less) Wi memory capacity to work.
Each workstation can use unlimited amount of memory banks, Total memory capacity of this workstation is the sum of capacity of all memory banks it used.
We need to make all workstations work and calculate the total capacity of unused memory banks, can you help us?

输入
Input is given from Standard Input in the following format:
X0 … X59
n
W1 … Wn
Constraints
0 ≤ Xi ≤ 260
1 ≤ n ≤ 100000
0 ≤ Wi ≤ 260
All of them are integers.

输出
Print one line denotes the answer.
If it is possible to make all workstations work, output a single number represents the total capacity of unused memory banks. It maybe very large, you should modulo 1000000007(109 + 7)
Otherwise output -1.

样例输入
4 2 2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0
3
10 8 16

样例输出
6

**题意:**有60种不同大小的内存块,容量分别为2^i (0<=i<=59)数组ai表示该容量内存块有几个,现在有n个需要分配内存容量的工作站,需要多少就分配多少,不能多也不能少,问分配后还剩多少空闲内存块。结果模1e9+7

**题解:**模拟题,首先明确一个工作站分配的过程中,一定是先用大块内存凑再用小块内存凑才是最优的,否则可能导致,小块内存用来凑大容量,结果小块内存用完了,而大块内存还有剩余,在后面需要小块内存凑剩余时,因为大块内存无法胜任(有大量多余情况),会出现能分配却凑不出来情况。因此按从大到小的顺序分配内存块种类。
其他操作就是直接取模除模拟减少的各个种类内存块数量即可。注意如果某个种类的数量不够时,那么应该直接将其全部分完,然后不足的部分加回来,让后面小容量种类继续分配。

#include<bits/stdc++.h>
#define LL long long
#define M(a,b) memset(a,b,sizeof a)
#define pb(x) push_back(x)
using namespace std;
const int maxn=1e5+7;
const int mod=1000000007;
LL a[80],b[maxn],c[80];
LL bin[69];
LL n;
LL qa(LL a,LL b)
{
    LL ans=0;
    while(b)
    {
        if(b&1)ans=(ans+a)%mod;
        a=(a+a)%mod;
        b>>=1;
    }
    return ans;
}
int main()
{
    bool flag=true;
    for(int i=0; i<60; i++)scanf("%lld",&a[i]),c[i]=1LL<<i;///初始化容量数组,表示第i种内存块容量为c【i】
    scanf("%lld",&n);
    for(int i=1; i<=n; i++) scanf("%lld",&b[i]);///输入每个工作站需要的内存量
    sort(b+1,b+1+n);
    for(int i=n; i>=1&&flag; i--)///按照从大到小的需求分配
    {
        LL tmp=b[i];
        for(int j=59; j>=0; j--)///对于每个工作站,如果能用大的内存块就尽量用大的,剩余部分用小的凑
        {
            if(tmp>=c[j])///如果工作站需要的容量大于当前内存块种类的容量,说明可以用当前种类来分
            {
                LL num=tmp/c[j];///需要num个j类块
                tmp=tmp%c[j];///分配后剩余不足j类块容量的
                if(a[j]>=num)a[j]-=num,num=0;///检查j类块是否有足够数量分配,如果有,需要的块数num清零,j类块数量减去分配出去的num块
                else///否则有多少分多少
                {
                    num-=a[j];///需要的块数减去剩余块数
                    a[j]=0;///j类块数量清零
                }
                tmp+=num*c[j];///最后如果需要的num块没有完全得到分配,那么剩余需求容量应该加回来,试探后面的小容量块是否能继续分配
            }
            if(j==0&&tmp) flag=false;///如果上面循环中60种块都遍历完了仍然没有分配干净需要的,说明输入的数量完全不够分,直接退出
        }
    }
    LL ans=0;
    if(!flag)printf("-1\n");///无法分配成功左右工作站
    else
    {
        for(int i=0; i<60; i++)if(a[i])ans=(ans+qa(a[i],c[i]))%mod;///剩余块直接加上数量数组中的每一种块容量即可,因为直接用 数量 乘 容量 可能会爆LL,因此用快速乘取模
        printf("%lld\n",ans);
    }

}


猜你喜欢

转载自blog.csdn.net/kuronekonano/article/details/82820495