Description
硬币购物一共有4种硬币。面值分别为c1,c2,c3,c4。某人去商店买东西,去了tot次。每次带di枚ci硬币,买si的价值的东西。请问每次有多少种付款方法。
Input
第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,s
Output
每次的方法数
Sample Input
1 2 5 10 2
3 2 3 1 10
1000 2 2 2 900
Sample Output
4
27
HINT
数据规模
di,s<=100000
tot<=1000
题解:因为数据范围比较大,所以考虑一下其他的方法。
然后就可以容斥一下。。
先处理出在没有硬币个数限制的情况下买价格为i的物品的方案数,记为f[i];
最后 ans=没有限制的方案数-至少有一个超过限制的方案数+至少有两个超过限制的方案数-至少有三个超过限制的方案数+全部超过限制的方案数。
对于超过限制的方案数的求法,我们可以这么考虑。先强制这超过限制的硬币选d+1个,看一下总和(temp)是不是会超过s,如果超过答案为0,否则答案为f[s-temp];
时间复杂度 O(s+tot);
#include<cstdio> #include<cstring> #include<iostream> #define N 100010 using namespace std; int n,s,c[5],d[5]; long long f[N],ans; long long cal(int x,int y,int p,int q) { int temp(0); temp=c[x]*(d[x]+1)+c[y]*(d[y]+1)+c[p]*(d[p]+1)+c[q]*(d[q]+1); return (temp>s?0:f[s-temp]); } int main() { for(int i=1;i<=4;i++) scanf("%d",&c[i]); scanf("%d",&n); f[0]=1; for(int j=1;j<=4;j++) for(int i=c[j];i<N;i++) f[i]+=f[i-c[j]]; for(int k=1;k<=n;k++) { for(int i=1;i<=4;i++)scanf("%d",&d[i]); scanf("%d",&s); ans=cal(0,0,0,0); ans-=cal(1,0,0,0);ans-=cal(2,0,0,0); ans-=cal(3,0,0,0);ans-=cal(4,0,0,0); ans+=cal(1,2,0,0);ans+=cal(1,3,0,0); ans+=cal(1,4,0,0);ans+=cal(2,3,0,0); ans+=cal(2,4,0,0);ans+=cal(3,4,0,0); ans-=cal(1,2,3,0);ans-=cal(1,2,4,0); ans-=cal(1,3,4,0);ans-=cal(2,3,4,0); ans+=cal(1,2,3,4); printf("%lld\n",ans); } }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-11-07 12:01:20