样例输入
1 1 2 2 1 1 2
样例输出
0 1
题意: 有n种船,第i船能载v[i]重量的货物,有(2^c[i])-1 艘第i种船,有q个询问 每个询问问你正好装s重量的货物的方案数(每艘船要装满)
思路:题目中 每种船的个数是关键。 对于 (2^c[i])-1 艘船 可以分为 2^0+2^1+2^2+...+2^(c[i]-1) 如果我们将每项分开当成一个单独的物品 通过选择其中的某几项 可以拼出任意小于 (2^c[i])-1的数 (也就是二进制表示十进制) 那么现在所以物品的数量都为一个 就可以用01背包求方案数 预处理出所有S的答案
我第一次遇到用背包求方案数的 dp[i][j] 表示用前i个物品达到重量为j
如果是求最大价值 dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]])
方案数为 dp[i][j]=dp[i-1][j]+dp[i-1][j-v[i]]
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<string>
#include<cstdio>
#include<stdio.h>
using namespace std;
typedef long long ll;
const ll mod= 1e9+7;
ll v[25];
ll c[25];
ll dp[10005];
int main()
{
int t;
scanf("%d",&t);
while(t--){
int n,q;
memset(dp,0,sizeof(dp));
dp[0]=1;
scanf("%d%d",&n,&q);
for(int i=0;i<n;i++){
scanf("%d%d",&v[i],&c[i]);
}
for(int i=0;i<n;i++){
for(int j=0;j<c[i];j++){
ll val=v[i]<<j;
for(int k=10001;k>=val;k--){
dp[k]+=dp[k-val];
dp[k]%=mod;
}
}
}
while(q--){
int s;
scanf("%d",&s);
printf("%lld\n",dp[s]);
}
}
return 0;
}