1. 程式人生 > >計蒜客 Transport Ship (2018-ACM-ICPC-焦作-網路賽)DP

計蒜客 Transport Ship (2018-ACM-ICPC-焦作-網路賽)DP

There are NN different kinds of transport ships on the port. The i^{th}ith kind of ship can carry the weight of V[i]V[i] and the number of the i^{th}ith kind of ship is 2^{C[i]} - 12C[i]−1. How many different schemes there are if you want to use these ships to transport cargo with a total weight of SS?

It is required that each ship must be full-filled. Two schemes are considered to be the same if they use the same kinds of ships and the same number for each kind.

Input

The first line contains an integer T(1 \le T \le 20)T(1≤T≤20), which is the number of test cases.

For each test case:

The first line contains two integers: N(1 \le N \le 20), Q(1 \le Q \le 10000)N(1≤N≤20),Q(1≤Q≤10000), representing the number of kinds of ships and the number of queries.

For the next NN lines, each line contains two integers: V[i](1 \le V[i] \le 20), C[i](1 \le C[i] \le 20)V[i](1≤V[i]≤20),C[i](1≤C[i]≤20), representing the weight the i^{th}ith kind of ship can carry, and the number of the i^{th}ith kind of ship is 2^{C[i]} - 12C[i]−1.

For the next QQ lines, each line contains a single integer: S(1 \le S \le 10000)S(1≤S≤10000), representing the queried weight.

Output

For each query, output one line containing a single integer which represents the number of schemes for arranging ships. Since the answer may be very large, output the answer modulo 10000000071000000007.

樣例輸入複製

1
1 2
2 1
1
2

樣例輸出複製

0
1

題目來源

題意: 有 n 種不同種類的船,每種船有一個 v 載重值,船有 2的 c 次方 - 1 艘

現在有 m 次詢問,每次詢問給出一批貨物的重量,問你有多少種安排方法把貨物放到船上,且每艘船必須裝滿

思路: 多重揹包,由於每艘船必須裝滿,並且詢問的是重量,那麼 dp[s] 表示載重為 s 的時候的方案數

那麼對於 第 i 種船如果安排 ai 艘,使得總載重達到 k ,那麼狀態轉移方程為:

dp[ k ] = ( dp[ k ] + dp[ k - ai * vi ] ) % mod  因為要統計方案數,所以直接加起來就可以了

因為船有 2 的 c 次方 - 1 艘,所以我們可以用二進位制的倍增法

即列舉該種類的船的數量為 1 2 4 8 16 32 64 ... 艘,並且是從小到大倍增的話,後面的情況會與前面的融合,就可以搭配出 

使用了 1 到 ( 2 的 c 次方 - 1) 艘該種類的船的所有情況

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a,x) memset(a,x,sizeof(a))

const int maxn = 1e4 + 5;
const int mod = 1e9 + 7;

ll dp[maxn];

int main(){
	int T, n, m;
	ll v,c;
	scanf("%d", &T);
	while(T--){
		mem(dp,0);
		dp[0] = 1;
		scanf("%d %d",&n, &m);
		for(int i = 1; i <= n; i++){
			scanf("%lld %lld", &v, &c);
			ll cnt = 1;
			for(ll j = 1; j <= c; j++){
				for(ll k = 10000; k >= cnt * v; k--){
					dp[k] = (dp[k] + dp[k - cnt * v]) % mod;
				}
				cnt <<= 1;
			}
		}
		for(int i = 1; i <= m; i++){
			scanf("%lld", &v);
			printf("%lld\n",dp[v]);
		}
	}	
	return 0;
}