洛谷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;
}
View Code

 

posted @ 2017-08-01 22:55  友人Aqwq  阅读(181)  评论(1编辑  收藏  举报