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 }