快速傅里葉變換(容斥+dp)

時間限制: 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;
}
/**/

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章