用动态规划做。思路是把所有的砝码展开,用数组w来保存砝码,例如原本有3个重量为9的法码,那就直接压入3个9到数组w中。 最后得到一个砝码数组。砝码数组中的砝码之和为max_weight,表示所有砝码加起来可以称量的最大重量。

动态规划数组dp[i]是一个布尔型数组,如果为真表示重量i可以被称量。

第一层循环所有砝码,第二层循环 1...max_weight,由于砝码w[i]的加入,假设是一个重量为5的砝码,当前要考虑的重量是8能不能被称量,如果dp[3]为true,即3能被称量,那么加上这个重量为5的砝码,则8一定能被称量。按这个思路,伪代码如下:

for i = 1 .. w.size:
  for j = 1 ... max_weight:
     if w[j - w[i]] == True:
         w[j] = True;

下面的C++代码实现中,使用到了滚动数组。另外,测试用例的最后一个用例是有问题的,因为题设中每组砝码的数量范围是[1, 6],但是测试用例的最后一组砝码数量是10。

#include <iostream>
#include <set>
#include <vector>

using namespace std;
bool dp[2010 * 100]; // 最后一组测试用例砝码数量用了10,这里需要乘以100,否则长度不够。

int main()
{
    int n;
    while(cin >> n)
    {
        vector<int>w;
        int max_weight = 0, tmp;
        w.push_back(0); // 无意义占位符
                
        for(int i = 1; i <= n; i++) { cin >> tmp; w.push_back(tmp); } 
        for(int i = 1; i <= n; i++)
        {
            cin >> tmp;
            for(int j = 0; j < tmp - 1; j++)
                w.push_back(w[i]);
            max_weight += tmp * w[i];
        }
        // 初始化动态规范数组
        for(int i = 0; i <= max_weight; i++)
            dp[i] = false;
        dp[0] = true; // 关键,初始启动
        // 动态规划查找
        for(int i = 1; i < w.size(); i++)
            for(int j = max_weight; j >= w[i]; j--)
                if(dp[j-w[i]]) dp[j] = true;
        // 统计结果
        int res = 0;
        for(int i = 0; i <= max_weight; i++)
            if(dp[i]) res++;
        cout << res << endl;
    }
    return 0;
}