洛谷P1450 [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
[HAOI2008]
这道题是道数论题 首先我们可以没有限制地像完全背包一样求出f【i】
f【i】表示硬币合起来是 i 的方案数
然后利用容斥原理 用总的方案数减去不合法的方案数就好啦
用递归实现代码比较简洁
类似于
总的方案数 -一种超的方案数和+两种超的方案数和-三种超的方案数和~~~~~~~~~
具体的容斥原理百度学学咯?
#include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; LL read(){ LL ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } LL s,c[5],d[5],T; LL ans,f[100007]; void rc(int i,int s,int k){ if(i==5){ ans+=f[s]*k; return ; } rc(i+1,s,k); if((LL)c[i]*(d[i]+1)<=s) rc(i+1,s-(c[i]*(d[i]+1)),-k); } int main() { c[1]=read(); c[2]=read(); c[3]=read(); c[4]=read(); T=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]]; while(T--){ d[1]=read(); d[2]=read(); d[3]=read(); d[4]=read(); s=read(); ans=0; rc(1,s,1); printf("%lld\n",ans); } return 0; }