Yet another game from chef. Chef gives you N cards and M bags. Each of the N cards has an integer written on it. Now chef asks you to close your eyes and choose a subset of them. He then sums the numbers written on chosen cards, takes its absolute value and gives you those many coins. You win the game if you can divide these coins into M bags with each bag having equal share. As a first step to calculate the probability of winning, you would like to know the number of different subsets which will make you win. Note that all the cards are of different color, so even if 2 cards have the same number written on it, they are still considered as different cards.
Input
The first line of the input contains an integer T denoting the number of test cases. The description of T test cases follows.
First line of each test case contains two integers N and Q. Q denotes the number of queries to be answered. Second line of each test case contains N integers, the numbers written on cards.
Following Q lines contain an integer M.Output
For each query output the required Answer modulo 1000000009. Answer is the number of subsets that will ensure you win.
Constraints
- 1 ≤ T ≤ 3
- 1 ≤ N ≤ 100000
- 1 ≤ Q ≤ 30
- 1 ≤ M ≤ 100
- -10^9 ≤ Number on card ≤ 10^9
Example
Input 2 5 1 1 2 -1 4 5 9 5 2 1 2 3 4 5 5 15 Output 4 8 2Explanation
Test Case #1, Query #1
{}, {1,-1}, {1,-1,4,5}, {4,5} are winning subsets. Sums are 0, 0, 9, 9 respectively.Test Case #2, Query #1
{}, {5}, {1,4}, {2,3}, {1,4,5}, {2,3,5}, {1,2,3,4}, {1,2,3,4,5} are winning subsets. Sums are 0, 5, 5, 5, 10, 10, 10, 15 respectively.Test Case #2, Query #2
{}, {1,2,3,4,5} are winning subsets. Sums are 0 and 15 respectively.Author's Note
Time Limit is not very strict (Yes, not very loose either) if correct Algorithm is used.Author's solution passes with 2 sec Time Limit (C++ solution, using scanf and printf).
Maximum Input File Size < 4MB.
题意:给出n个数,然后还有一个数字m,问有多少种方法可以从n个数中选出一些数使得这些数的和是m的倍数。
很好的一道题,学到了很多。首先对于自己的基础之差感动汗颜。
第一,对C(n, k)的打表。。。这里还是说下自己的想法吧,如果n<10^3,这个数据量基本是可以用递推的,二维数组C[n][k]记录。
像这题的n<10^5,显然无法开出巨表,所以可以使用C(n, k) = n!/(k! * (n -k)!)..这样就可以通过记录n!和n!的逆来进行求解,
如果题目给出的模数是个质数,就可以通过费马小定理很方便的求出一个数的逆元,当然扩展gcd也是可以的。
其次,对于这题的思路,看到题目和数据范围就应该想到实际上真正的数据范围就只有[0, m)...所以每次询问直接将A[i]模m,然后
得到每个数出现的次数。这样就可以得到dp的基本模型了。
dp[i][j]表示从0到i这些数中选一些数模m为j的方案数,然后dp[i][j]可以从dp[i-1][0..m-1]得到。
Accepted Code:
1 /************************************************************************* 2 > File Name: ANUCBC.cpp 3 > Author: Stomach_ache 4 > Mail: [email protected] 5 > Created Time: 2014年09月04日 星期四 14时13分00秒 6 > Propose: 7 ************************************************************************/ 8 #include <cmath> 9 #include <string> 10 #include <cstdio> 11 #include <fstream> 12 #include <cstring> 13 #include <iostream> 14 #include <algorithm> 15 using namespace std; 16 /*Let's fight!!!*/ 17 18 #define rep(i, n) for (int i = (0); i < (n); i++) 19 #define FOR(i, a, b) for (int i = (a); i <= (b); i++) 20 const int MAX_N = 100050; 21 const int MAX_M = 101; 22 const int MOD = 1e9 + 9; 23 typedef long long LL; 24 LL fact[MAX_N], ifact[MAX_N]; 25 26 LL pow_mod(LL a, LL b) { 27 LL res = 1; 28 while (b) { 29 if (b & 1) res = (res * a) % MOD; 30 a = (a * a) % MOD; 31 b >>= 1; 32 } 33 return res; 34 } 35 36 //fact and ifact 37 void init() { 38 fact[0] = fact[1] = ifact[0] = ifact[1] = 1; 39 FOR (i, 2, MAX_N - 50) { 40 fact[i] = (fact[i - 1] * i) % MOD; 41 ifact[i] = (ifact[i - 1] * pow_mod(i, MOD - 2)) % MOD; 42 } 43 } 44 45 int C(int n, int k) { 46 return (fact[n] * ifact[k] % MOD) * ifact[n - k] % MOD; 47 } 48 49 int A[MAX_N], cnt[MAX_M]; 50 LL dp[MAX_M][MAX_M], choose[MAX_M][MAX_M]; 51 52 int main(void) { 53 init(); // precomputation 54 55 ios::sync_with_stdio(false); 56 int T; 57 cin >> T; 58 while (T--) { 59 int N, Q, M; 60 cin >> N >> Q; 61 rep (i, N) cin >> A[i]; 62 while (Q--) { 63 cin >> M; 64 memset(cnt, 0, sizeof(cnt)); 65 rep (i, N) cnt[(A[i] % M + M) % M]++; 66 67 memset(choose, 0, sizeof(choose)); 68 rep (i, M) FOR (j, 0, cnt[i]) { 69 choose[i][j * i % M] = (choose[i][j * i % M] + C(cnt[i], j)) % MOD; 70 } 71 72 memset(dp, 0, sizeof(dp)); 73 dp[0][0] = choose[0][0]; 74 FOR (i, 1, M-1) rep (j, M) rep (k, M) dp[i][j] = (dp[i][j] + dp[i - 1][(j - k + M) % M] * choose[i][k]) % MOD; 75 76 cout << dp[M - 1][0] << endl; 77 } 78 } 79 return 0; 80 }