ACM-ICPC 2018 焦作赛区网络预赛 Transport Ship
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string.h>
using namespace std;
int v[20], c[20];
int dp[10001];
const int mod = 1e9 + 7;
int main()
{
int t,n,q,V; cin >> t;
while (t--)
{
cin >> n >> q;
for (int i = 0; i < n; i++)
scanf("%d%d", &v[i], &c[i]);
memset(dp, 0, sizeof(dp));
//多重背包与01背包不同的是每一种物品不止一个,但不是无限个
//如果一个一个枚举显然复杂度很大
//我们把同一种物品拆分多个01背包的物品
//把每种物品的数量拆成2^0,2^1,…,2^c[i]-1
//从二进制的角度看可以表示小于等于它的任意一个数,把这些作为v[i]的系数
//再转化为01背包来解即可
dp[0] = 1;
for (int i = 0; i < n; i++)
{
for (int k = 0; k < c[i]; k++)
{
V = v[i] << k;
for (int j = 10000; j >= V; j--)
{
//dp[j]=dp[j]+dp[j-V]
//二进制的每一位要么取,要么不取
dp[j] += dp[j - V];
dp[j] %= mod;
}
}
}
for (int i = 0; i < q; i++)
{
scanf("%d", &V);
printf("%d\n", dp[V]);
}
}
return 0;
}