bzoj 1531: [POI2005]Bank notes 單調隊列優化多重背包


題目

Description

Byteotian Bit Bank (BBB) 擁有一套先進的貨幣系統,這個系統一共有n種面值的硬幣,面值分別為b1, b2,…, bn. 但是每種硬幣有數量限制,現在我們想要湊出面值k求最少要用多少個硬幣.

Input

第一行一個數 n, 1 <= n <= 200. 接下來一行 n 個整數b1, b2,…, bn, 1 <= b1 < b2 < … < b n <= 20 000, 第三行 n 個整數c1, c2,…, cn, 1 <= ci <= 20 000, 表示每種硬幣的個數.最后一行一個數k – 表示要湊的面值數量, 1 <= k <= 20 000.

Output

第一行一個數表示最少需要付的硬幣數

Sample Input

3

2 3 5

2 2 1

10

Sample Output

3

分析

神牛:一大早又虐了一道水題。
我:一大晚的還被水題虐。

裸的單調隊列維護多重背包,但因為好久沒寫了,所以就調了有一段時間。就當是復習模板了。

代碼

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define N 205
#define M 20005
#define inf 0x3f3f3f3f
using namespace std;

int b[N],c[N],f[M],q[M],w[M];

int main()
{
    int n,m;
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%d",&b[i]);
    for (int i=1;i<=n;i++)
        scanf("%d",&c[i]);
    scanf("%d",&m);
    memset(f,inf,sizeof(f));
    f[0]=0;
    for (int i=1;i<=n;i++)
    {
        for (int j=0;j<b[i];j++)
        {
            int head=1,tail=0;
            for (int k=j;k<=m;k+=b[i])
            {
                while (head<=tail&&w[head]<k-c[i]*b[i]) head++;
                while (head<=tail&&f[k]-(k-w[head])/b[i]<=q[tail]) tail--;
                q[++tail]=f[k];
                w[tail]=k;
                f[k]=min(f[k],q[head]+(k-w[head])/b[i]);
            }
        }
    }
    printf("%d",f[m]);
    return 0;
}

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com