Skip to content

14126: 【原4126】Spice and Wolf II

题目

题目描述

author: 黄俊翔 原OJ链接:https://acm.sjtu.edu.cn/OnlineJudge-old/problem/4126 ## Description

赫萝与罗伦斯正在米隆商行进口香辛料(胡椒),准备运到帕兹欧去卖掉。但米隆商行店大欺客,在找零时对于一崔尼银币以下的面额是一概不找的,因此赫萝希望在商行报价时能精确的给出所需的金额而无需找零。但是赫萝并不知道商行的报价会是多少,因此赫萝让罗伦斯拿出了身上所有的金币、银币和铜币。

这可是个大工程。因为中世纪时,有多个国家和商行都在发行货币,而且汇率还随着货币公信力经常变化,比现代货币还复杂。比方说,1卢米欧金币=24~40枚崔尼银币,1崔尼银币又能换到20+枚路德银币,1路德银币又能换3托里尤铜币(你看,1崔尼银币能换60+托里尤铜币,不给找零岂不是很坑)。这只是其中的四种货币,实际上当时同一个区域流通的货币种类甚至能达到几十种。所幸的是,所有的货币价值都是托里尤铜币的整数倍,因此所有的金额都可以用一个整数表示。

为了尽量节省找零的钱来买苹果,赫萝希望能算出罗伦斯能精确支付的金额有多少种。你能帮帮她吗?

Input Format

第一行包含一个正整数\(T\),为测试数据的组数。

每组测试数据为两行。

第一行为两个正整数\(N, M\),其中\(N\)代表总共有多少种钱币,而\(M\)则代表赫萝预期购买胡椒的总花费不会超过\(M\)枚托里尤铜币,因此她只需要知道\(M\)及以内的金额有多少种可以精确支付。

第二行为\(2N\)个正整数,格式为\(A_1, A_2, ..., A_N, C_1, C_2, ..., C_N\)。其中\(A_i\)表示第\(i\)种钱币相当于多少枚托里尤铜币,\(C_i\)表示第\(i\)种钱币有多少枚。

Output Format

每组测试数据对应输出一行,代表\(M\)枚托里尤铜币及以内的金额有多少种可以精确支付。

Sample Input

2
3 10
1 2 4 2 1 1
2 5
1 4 2 1

Sample Output

8
4

Data Range

对于\(30\%\)的数据,\(sum(C_i) \le 20\)。

对于\(60\%\)的数据,\(sum(C_i) \le 100\)。

对于额外\(20\%\)的数据,罗伦斯超级有钱,以至于对于任意的\(i\)都有\(A_i * C_i \ge M\)。友情提示1:罗伦斯不一定有托里尤铜币,请不要打输出\(M\)的主意。友情提示2:数据并不保证\(A_i * C_i < 2^{31} \approx 2 * 10^9\)。

对于\(100\%\)的数据,\(T \le 5\),\(N \le 100\),\(M,A_i,C_i \le 100000\)。

友情提示3:这次的正解还是30行。当然60分也是30行。80分约是30+10行。又是熟悉的30分骗分最长系列。

WashSwang's solution

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int t,n,m,dp[100001],k,ans;
long long a[101],c[101];
void zeroone(int w)
{
    for (int i=m;i>=w;--i)
        if (dp[i-w]) dp[i]=1;
}
void complete(int w)
{
    for (int i=w;i<=m;++i)
        if (dp[i-w]) dp[i]=1;
}
int main() {
    scanf("%d",&t);
    for (int i=0;i<t;++i)
    {
        ans=0;
        scanf("%d%d",&n,&m);
        memset(dp,0,sizeof(dp));
        dp[0]=1;
        for (int j=0;j<n;++j) scanf("%lld",&a[j]);
        for (int j=0;j<n;++j) {
            scanf("%lld",&c[j]);
            if (a[j]*c[j]<m)
            {
                k=1;
                while (k<c[j])
                {
                    zeroone(k*a[j]);
                    c[j]-=k;
                    k*=2;
                }
                zeroone(c[j]*a[j]);
            }
            else
                complete(a[j]);
        }
        for (int j=1;j<=m;++j)
            if (dp[j]) ++ans;
        printf("%d\n",ans);
    }
    return 0;
}