BZOJ 1042 HAOI2008 硬币购物
1042: [HAOI2008]硬币购物 Time Limit: 10 Sec Memory Limit: 162 MB Submit: 2903 Solved: 1785 [Submit][Status][Discuss] Description 硬币购物一共有4种硬币。面值分别为c1,c2,c3,c4。某人去商店买东西,去了tot次。每次带di枚ci硬币,买s i的价值的东西。请问每次有多少种付款方法。 Input 第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,s,其中di,s<=100000,tot<=1000 Output 每次的方法数 Sample Input 1 2 5 10 2 3 2 3 1 10 1000 2 2 2 900 Sample Output 4 27
DP预处理+容斥原理。 以前没写过容斥原理,所以这里写下笔记吧。 若用一个01串表示方案种类,第I位为1表示满足D[I]条件,为0表示不满足的话。 那么,我们要求的即是1111。 显然,就是 所有情况(至少有0个0的情况)-至少有一个0的情况+至少有两个0的情况...【减加减加】 即 ANS=0个0=(0个0,1个0,2个0..)-(1个0,2个0,3个0..)+(2个0,3个0..).. 也就是说,减去所有至少偶奇数个0的情况,加上所有至少偶数个0的情况。 这个可以用DFS来做。 每一层即一个位I,可以转移到不受限制的情况(这一位0或1)或者(这一位0)的情况。分别不改颜色和改颜色。 也可以直接循环去枚举 我代码写的是循环去枚举要还是删掉 还是太弱了QAQ
1 #include <bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 inline ll read(){ 5 ll x=0;ll f=1;char ch=getchar(); 6 while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();} 7 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 8 return x*f; 9 } 10 ll f[300010]={}; 11 int c[5],d[5]; 12 namespace zhangenming{ 13 void init(){ 14 c[1]=read();c[2]=read();c[3]=read();c[4]=read(); 15 f[0]=1; 16 for(int i=1;i<=4;i++){ 17 for(int j=c[i];j<=200100;j++){ 18 f[j]+=f[j-c[i]]; 19 } 20 } 21 } 22 void solve(){ 23 ll tot=read(); 24 for(int i=1;i<=tot;i++){ 25 for(int i=1;i<=4;i++){ 26 d[i]=read(); 27 } 28 ll ans=0; 29 ll s=read(); 30 if(s>d[1]*c[1]+d[2]*c[2]+d[3]*c[3]+d[4]*c[4]){ 31 printf("%lld\n",ans);continue; 32 } 33 ans=f[s]; 34 for(ll i=1;i<=4;i++){ 35 if(s>=(d[i]+1)*c[i]) ans-=f[s-(d[i]+1)*c[i]]; 36 } 37 for(ll i=1;i<=4;i++){ 38 for(ll j=i+1;j<=4;j++){ 39 if(s>=(d[i]+1)*c[i]+(d[j]+1)*c[j]) ans+=f[s-(d[i]+1)*c[i]-(d[j]+1)*c[j]]; 40 } 41 } 42 for(ll i=1;i<=4;i++){ 43 for(ll j=i+1;j<=4;j++){ 44 for(ll k=j+1;k<=4;k++){ 45 if(s>=(d[i]+1)*c[i]+(d[j]+1)*c[j]+(d[k]+1)*c[k]) ans-=f[s-(d[i]+1)*c[i]-(d[j]+1)*c[j]-(d[k]+1)*c[k]]; 46 } 47 } 48 } 49 if(s>=((d[1]+1)*c[1]+(d[2]+1)*c[2]+(d[3]+1)*c[3]+(d[4]+1)*c[4])){ 50 ans+=f[s-(d[1]+1)*c[1]-(d[2]+1)*c[2]-(d[3]+1)*c[3]-(d[4]+1)*c[4]]; 51 } 52 53 printf("%lld\n",ans); 54 } 55 } 56 } 57 int main(){ 58 //freopen("A+B.in","r",stdin); 59 //freopen("A+B.out","w",stdout); 60 using namespace zhangenming; 61 init(); 62 solve(); 63 return 0; 64 }