UVA 11259 Coin Changing Again

题意:有4种硬币,面值分别为c1,c2,c3,c4,然后给出Q组查询。每组查询给出5个数d1,d2,d3,d4,v,分别表示面值为ci的硬币共有di个,然后要求将其凑成总值为v的方案数。

数据范围大致是c<=1000,Q<=100,d,v<=100000。

如果按照普通分组背包的做法,对每组Q都做一遍DP,那么这个复杂度就会达到10^9的级别,肯定会TLE。我也拿不出太好的办法,觉得这题DP不出来。

其实,这题不完全是DP,我觉得这个题目的核心是容斥原理。对于每组查询,算法的复杂度基本上是O(1)这样的常数级的。

在UVA的论坛里看到了大牛的解释:

假设现在只有两种硬币,我们令N=所有凑出v总值的方案数,N1=第一种面值为c1的硬币取了超过d1次凑出总值v的方案数,N2=第二种面值为c2的硬币取了超过d2次凑出总值v的方案数,N12=第一种面值为c1的硬币取了超过d1次且N第二种面值为c2的硬币取了超过d2次凑出总值v的方案数。那么对于一组查询d1,d2,v,合法的方案数就是N-N1-N2+N12.

为了计算这些N,我们利用c1,c2,c3,c4先做一遍背包容量为100000的无限背包,用dp数组记录方案数。

那么计算N的话,直接算用dp[v]就可以了。

怎么计算N1呢?因为c1硬币取了超过了d1次,那么我们就假设它取了d1+1次,共取走了(d1+1)*c1价值的硬币,那么方案数就是dp[v-(d1+1)*c1]。

同理,N2的方案数就是dp[v-(d2+1)*c2],N12的方案数就是dp[v-(d1+1)*c1-(d2+1)*c2]。然后统计N-N1-N2+N12,就可以得到答案了。

现在问题中的硬币种类边成了4个,还是用一样的原理,这时候答案就是N-N1-N2-N3-N4+N12+N13+N14+N23+N24+N34-N123-N124-N134-N234+N1234,一共16项。

 1 #include <cstdio>
 2 typedef long long LL;
 3 LL dp[100010];
 4 
 5 int main(){
 6     int c[4],d[4],v,Q,kase;
 7     scanf("%d",&kase);
 8     while(kase--){
 9         dp[0] = 1;
10         for(int i = 1;i <= 100000;i++)  dp[i] = 0;
11 
12         for(int i = 0;i < 4;i++)
13             scanf("%d",&c[i]);
14 
15         for(int i = 0;i < 4;i++)
16             for(int j = c[i];j <= 100000;j++)
17                 dp[j] += dp[j-c[i]];
18 
19         scanf("%d",&Q);
20 
21         while(Q--){
22             LL ans = 0;
23 
24             for(int i = 0;i < 4;i++)
25                 scanf("%d",&d[i]);
26 
27             scanf("%d",&v);
28 
29             for(int i = 0;i < 16;i++){
30                 int tmp = v;
31                 int flag = 1;
32                 for(int j = 0;j < 4;j++){
33                     if(i&(1<<j)){
34                         flag = -flag;
35                         tmp -= (d[j]+1) * c[j];
36                     }
37                 }
38                 if(tmp >= 0)    ans += flag * dp[tmp];
39             }
40 
41             printf("%lld\n",ans);
42         }
43     }
44     return 0;
45 }
View Code

 

posted @ 2013-11-12 22:56  浙西贫农  阅读(479)  评论(0编辑  收藏  举报