P1450 [HAOI2008]硬币购物

原题链接

考察:容斥原理+完全背包+计数dp

本蒟蒻是打死都想不到怎么用容斥原理...

错误思路:

       乍看一下是多重背包,时间复杂度80*105*103(采用二进制优化)显然T了

正确思路:

       采取完全背包预处理的方法,时间复杂度105 ,求出不限数量的取法.答案就是所有取法-不合法的取法.这里就可以想到容斥原理了.

       如果要用容斥原理的话,还需要计数dp的思想.不合法的方案至少用了d[i]+1个c[i].这个的方案数等同于f[s-(d[i]+1)*c[i]].接下来就是容斥原理.

注意:答案是long long

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstring>
 5 using namespace std;
 6 typedef long long ll;
 7 const int N = 1e5+10;
 8 int d[5],c[5];
 9 ll f[N];
10 int main() 
11 {
12     int tot,s;
13     scanf("%d%d%d%d%d",&c[1],&c[2],&c[3],&c[4],&tot);
14     f[0] = 1;
15     for(int i=1;i<=4;i++)
16       for(int j=c[i];j<=1e5;j++) f[j] = f[j]+f[j-c[i]];
17     while(tot--)
18     {
19         ll ans = 0;
20         for(int i=1;i<=4;i++) scanf("%d",&d[i]);
21         scanf("%d",&s);
22         for(int i=1;i<1<<4;i++)
23         {
24             int cnt = 0; ll res = 0;
25             for(int j=0;j<4;j++)
26             {
27                 if(i>>j&1)
28                 {
29                     if(res+(ll)(d[j+1]+1)*c[j+1]>s)
30                     {
31                         res = -1;
32                         break;
33                     }
34                     cnt++; res= res+(ll)(d[j+1]+1)*c[j+1];
35                 }
36             }
37             if(res!=-1)
38               if(cnt&1) ans+=f[s-res];
39               else ans-=f[s-res];
40         }
41         printf("%lld\n",f[s]-ans);
42     }
43     return 0;
44 }

 

posted @ 2021-02-12 17:23  acmloser  阅读(41)  评论(0编辑  收藏  举报