時間限制: 1 Sec 內存限制: 128 MB
題目描述
chen_03在切快速傅里葉變換(FFT)。
一共有n種FFT的題,他做出一道第i種題後能獲得ci點的巨佬值。
他一共要打m場模擬賽,由於Rainy7的魔法,每次賽前,他的巨佬值會清零。
chen_03不希望他的巨佬值爲0。爲了獲得一些巨佬值,每場模擬賽前,他都要去切FFT的題。然而他太巨了,Rainy7爲了限制他的實力,又施了一個魔法,使得第i種題只有di道,且每道題在切完後會消失。
對於每場模擬賽,chen_03都有一個幸運數字,他想要知道在每場模擬賽前,他有多少種切題方式使他的巨佬值恰好等於s。
由於Rainy7的法力不穩定,每場模擬賽後di會更新,但ci不更新。
輸入
第一行一個正整數,表示n。
第二行n個正整數以空格隔開,第i個數表示ci。
第三行一個正整數,表示m。
接下來m行,每行n+1個數,以空格隔開。在第r行中,前n個數中第i個數表示第r場模擬賽前的di。最後一個數表示第r場模擬賽的s。
輸出
輸出m行,每行一個正整數,表示 chen_03 每次模擬賽前的切題方案數。
樣例輸入 Copy
3 9 4 4 3 0 0 3 12 1 9 6 69 3 5 0 47
樣例輸出 Copy
1 1 1
提示
預處理n種物品不限量對s(<=200000)的方案數dp
對於每一次的詢問,根據容斥原理,s的不限量方案數-選擇一種物品的超過限制量的方案數+選擇兩種物品的超過限制令的方案數-.....
超過限制的求法:比如第一種物品限制爲d[1],那麼選擇d[i] + 1個第一種物品,其他隨意選擇即爲超過超過限制的方案數dp[s - c[1] * (d[1] + 1)]
/**/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>
typedef long long LL;
using namespace std;
int n, m, c[7], d[7];
LL dp[200005], ans;
void dfs(int x, int num, int sum){
if(sum < 0) return ;
if(x == n + 1){
if(num & 1) ans -= dp[sum];
else ans += dp[sum];
return ;
}
dfs(x + 1, num + 1, sum - (d[x] + 1) * c[x]);
dfs(x + 1, num, sum);
}
int main()
{
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &c[i]);
dp[0] = 1;
for (int i = 1; i <= n; i++){
for (int j = c[i]; j <= 200000; j++){
dp[j] += dp[j - c[i]];
}
}
scanf("%d", &m);
for (int i = 1, s; i <= m; i++){
for (int j = 1; j <= n; j++) scanf("%d", &d[j]);
scanf("%d", &s);
ans = 0;
dfs(1, 0, s);
printf("%lld\n", ans);
}
return 0;
}
/**/