有三种硬币,每种有自己的币值。
然后有n次询问,每次都给出每种硬币的数量和要付的钱s,求有多少种付法。n<=1000 s<=100000
------
不考虑限制,就是个简单dp....
有限制的时候,我们可以考虑反过来用总的方案数量剪掉不合法的。
根据容斥原理,不合法的情况=
有1种硬币数量不合法即第1种不合法+第2+第3+第4 再去掉有两个不合法的12种都不合法-23种都不合法-34种都不合法-........加上三种不合法的即123种不合法+124不合法... 最后减去1234都不合法。
所以每次询问都这样做一遍,让一种硬币不合法只要付比他的限制多一个就可以了,剩下的钱可以随意付,直接去dp里查值。
复杂度4*s+n*2^4
#include#include #define ll long long using namespace std; inline int read() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){ if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}return x*f; }ll ans; int c[5],x[5],n,s; ll f[100005];void dfs(int i,int p,int sum) {// printf("%d %d %d ",i,p,sum);if(i>4){ans+=p*f[sum];return;}dfs(i+1,p,sum);if(sum>=c[i]*(x[i]+1))dfs(i+1,-p,sum-c[i]*(x[i]+1)); }int main() {for(int i=1;i<=4;i++)c[i]=read();f[0]=1;for(int i=1;i<=4;i++)for(int j=c[i];j<=100000;j++)f[j]+=f[j-c[i]];n=read();for(int i=1;i<=n;i++){for(int j=1;j<=4;j++)x[j]=read();s=read();ans=0;dfs(1,1,s);printf("%lld ",ans);}return 0; }