[HAOI2008]硬币购物
题目描述
硬币购物一共有4种硬币。面值分别为c1,c2,c3,c4。某人去商店买东西,去了tot次。每次带di枚ci硬币,买si的价值的东西。请问每次有多少种付款方法。
输入输出格式
输入格式:
第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,s
输出格式:
每次的方法数
输入输出样例
输入样例#1:
1 2 5 10 2 3 2 3 1 10 1000 2 2 2 900
输出样例#1:
4 27
说明
di,s<=100000
tot<=1000
题解:
一开始认为要求出一个4元方程的解的个数,用容斥求出所有GCD(a,b,c,d)|si的解
但时间复杂度太高,且条件限制不好做。
后面看到一种解法:
用dp求f[i]为钱数为i时的方案总数
显然f[i]=signma(f[i-c[j]])
复杂度为O(4*s)
再用容斥原理求出所有方案,减去1超出限制,再减去2超限,还有3和4。再加上1,2超限.....
i超出限制的方案为f[si-(d[j]+1)*c[j]]
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 long long c[5],d[5],tot; 7 long long f[1000005],ans; 8 int main() 9 {long long i,j,s; 10 cin>>c[1]>>c[2]>>c[3]>>c[4]>>tot; 11 f[0]=1; 12 for (i=1;i<=4;i++) 13 for (j=c[i];j<=100000;j++) 14 { 15 f[j]+=f[j-c[i]]; 16 } 17 for (i=1;i<=tot;i++) 18 { 19 for (j=1;j<=4;j++) 20 scanf("%I64d",&d[j]); 21 scanf("%I64d",&s); 22 ans=f[s]; 23 if ((d[1]+1)*c[1]<=s) 24 ans-=f[s-(d[1]+1)*c[1]]; 25 if ((d[2]+1)*c[2]<=s) 26 ans-=f[s-(d[2]+1)*c[2]]; 27 if ((d[3]+1)*c[3]<=s) 28 ans-=f[s-(d[3]+1)*c[3]]; 29 if ((d[4]+1)*c[4]<=s) 30 ans-=f[s-(d[4]+1)*c[4]]; 31 32 if ((d[1]+1)*c[1]+(d[2]+1)*c[2]<=s) 33 ans+=f[s-(d[1]+1)*c[1]-(d[2]+1)*c[2]]; 34 if ((d[1]+1)*c[1]+(d[3]+1)*c[3]<=s) 35 ans+=f[s-(d[1]+1)*c[1]-(d[3]+1)*c[3]]; 36 if ((d[1]+1)*c[1]+(d[4]+1)*c[4]<=s) 37 ans+=f[s-(d[1]+1)*c[1]-(d[4]+1)*c[4]]; 38 if ((d[3]+1)*c[3]+(d[2]+1)*c[2]<=s) 39 ans+=f[s-(d[3]+1)*c[3]-(d[2]+1)*c[2]]; 40 if ((d[4]+1)*c[4]+(d[2]+1)*c[2]<=s) 41 ans+=f[s-(d[4]+1)*c[4]-(d[2]+1)*c[2]]; 42 if ((d[3]+1)*c[3]+(d[4]+1)*c[4]<=s) 43 ans+=f[s-(d[3]+1)*c[3]-(d[4]+1)*c[4]]; 44 45 if ((d[1]+1)*c[1]+(d[2]+1)*c[2]+(d[3]+1)*c[3]<=s) 46 ans-=f[s-(d[1]+1)*c[1]-(d[2]+1)*c[2]-(d[3]+1)*c[3]]; 47 if ((d[4]+1)*c[4]+(d[2]+1)*c[2]+(d[3]+1)*c[3]<=s) 48 ans-=f[s-(d[4]+1)*c[4]-(d[2]+1)*c[2]-(d[3]+1)*c[3]]; 49 if ((d[1]+1)*c[1]+(d[4]+1)*c[4]+(d[3]+1)*c[3]<=s) 50 ans-=f[s-(d[1]+1)*c[1]-(d[4]+1)*c[4]-(d[3]+1)*c[3]]; 51 if ((d[1]+1)*c[1]+(d[4]+1)*c[4]+(d[2]+1)*c[2]<=s) 52 ans-=f[s-(d[1]+1)*c[1]-(d[4]+1)*c[4]-(d[2]+1)*c[2]]; 53 54 if ((d[1]+1)*c[1]+(d[2]+1)*c[2]+(d[3]+1)*c[3]+(d[4]+1)*d[4]<=s) 55 ans+=f[s-(d[1]+1)*c[1]-(d[2]+1)*c[2]-(d[3]+1)*c[3]-(d[4]+1)*d[4]]; 56 cout<<ans<<endl; 57 } 58 }