1. 程式人生 > >洛谷P1450 [HAOI2008]硬幣購物

洛谷P1450 [HAOI2008]硬幣購物

opened define printf 容斥原理 view 兩種 背包 請問 string

題目描述

硬幣購物一共有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

洛谷P1450 [HAOI2008]硬幣購物