1. 程式人生 > >【2018年東北賽】UPC-7226 Memory Banks(模擬儲存)

【2018年東北賽】UPC-7226 Memory Banks(模擬儲存)

題目描述 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);
    }

}