codechef:April Challenge 2014: Cards, bags and coins

http://www.codechef.com/APRIL14/problems/ANUCBC

Statement

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 Ttest cases follows.
First line of each test case contains two integers N and QQ 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
2

Explanation

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.


解决思路:

题意说的很繁琐,其实就是一句话,问一个集合的子集元素和为m(取模)的子集个数。看似有点像背包的思路,但不尽然。

因为这道题,对m取模,因此其复杂度可以降到很低。

思路1,O(n*m*q)

dp[i][j]表示前i个数构成的集合,其子集和为j的种类数。

转移是O(1): dp[i][j]=dp[i-1][j-num[i]]+dp[i-1][j]

而即使是这样,居然超时了。n=100000,m=100,q=30.

思路2,O(m^3*q)

考虑到n比较大,而m比较小,因此n个数对m取模之后肯定重复的数很多。

cnt[r]表示n个数中对m取模余数为r的个数,0<=r<m, 因此将n个数分为m堆,每一堆有cnt[r]个。注意cnt[r]也会很大。

对于第r堆,其自身的组合,r,2r,3r...对m取模之后,依然最多也只有m个,m<cnt[r].

因此add[r][j]表示仅考虑第r堆,组合成j的所有种类数。add[r][r*t%m] =Sum( C(cnt[r],t)

求得add之后,通过m^3的转移,就可以计算最后的结果。

dp[0][0]=1;
FOR(i,0,m)
FOR(j,0,m)//rep j
FOR(r,0,m)//combine r
dp[i+1][j] = ( dp[i+1][j] + dp[i][(j-r+m)%m] * add[i][r] % MOD )%MOD;

计算add的复杂度是O(n),其中组合数的计算,需要优化,否则依然超时。

计算dp的复杂度是m^3,

因此复杂度O(m^3*q)。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值