(mathcal{color{red}{Description}})
硬币购物一共有(4)种硬币。面值分别为(c_1,c_2,c_3,c_4)。某人去商店买东西,去了(tot)次。每次带(d_i)枚(c_i)硬币,买(s_i)的价值的东西。请问每次有多少种付款方法。
(mathcal{color{red}{Solution}})
好的,比较欣喜的一点是我们如果不考虑什么带了(k_i) 个,那么其实就是一个完全背包是不是……但是他有一个特别(zz)的限制条件。那我们不妨考虑从总方案数里面减去不合法的方案。但是吧,会有重复减这种情况,所以我们还要容斥。
那么套用容斥原理的基本公式,就可以得到(Ans)
还有一点,就是如何计算不合法的方案呢?
我们思考对于完全背包的递推式大概长这样:$$f_i = sumlimits_{j=1}^{4}f_{i-c_j}$$
那么也就是对于所有不合法的状态比如(f_{i - (d_j + t imes c_j)},t geq 1)都会有着这样的递推式$$f_{i-(d_j+T) imes c_j} = sum limits_{t geq T}f_{i - (d_j + t imes c_j)}$$
那么也就是说对于最终结果,就存在(f_{i - ((d_j + 1) imes c_j)}) 里面
// luogu-judger-enable-o2
#include <cstdio>
#include <iostream>
#define MAXN 5
#define MAX 100010
#define ll long long
using namespace std ; ll T, Ans ;
ll N, C[5], F[MAX], D[5], S, i, j, k ;
inline ll qr(){
ll k = 0 ; char c = getchar() ;
while(!isdigit(c)) c = getchar() ;
while(isdigit(c)) k = (k << 1) + (k << 3) + c - 48, c = getchar() ;
return k ;
}
inline ll WORK(ll X){
ll Y = S, Mark = 1 ;
for (k = 0 ;k < 4 ;++ k)
if ((X >> k) & 1)
Y -= (D[k + 1] + 1) * C[k + 1], Mark = -Mark ;
return Y < 0 ? 0 : F[Y] * Mark ;
}
int main(){
F[0] = 1 ;
for (i = 1 ; i <= 4 ; ++ i) cin >> C[i] ;
for (i = 1 ; i <= 4 ; ++ i)
for (j = C[i] ; j < MAX ; ++ j)
F[j] += F[j - C[i]] ; cin >> T ;
for (i = 1 ; i <= T ; ++ i){
Ans = 0, D[1] = qr(), D[2] = qr(), D[3] = qr(), D[4] = qr(), S = qr() ;
for (j = 0 ; j < 16 ; ++ j) Ans += WORK(j) ;
printf("%lld
", Ans) ;
}
return 0 ;
}