1042: [HAOI2008]硬币购物
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1534 Solved: 897
[ Submit][ Status][ Discuss]
Description
硬币购物一共有4种硬币。面值分别为c1,c2,c3,c4。某人去商店买东西,去了tot次。每次带di枚ci硬币,买si的价值的东西。请问每次有多少种付款方法。
Input
第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,s
Output
每次的方法数
Sample Input
1 2 5 10 2
3 2 3 1 10
1000 2 2 2 900
3 2 3 1 10
1000 2 2 2 900
Sample Output
4
27
27
HINT
数据规模
di,s<=100000
tot<=1000
Source
容斥原理呀!(苟蒻根本不会数学)
设f[i]为硬币数任意,凑齐i元方案数。。。
所以s元方案数 = f[s] - 使用c1超额方案数 - 使用c2超额方案数 - ... + 使用c1c2超额方案数 +...-使用c1c2c3超额方案数 - ...+使用c1c2c3c4超额方案数
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 1e5 + 10;
typedef long long LL;
LL f[maxn],d[4],c[4],m,n,ans;
int i,j;
void dfs(int k,int tot,LL sum)
{
if (n - sum < 0) return;
if (k == 4)
{
if (n - sum >= 0 && tot)
{
if (tot & 1) ans -= f[n - sum];
else ans += f[n - sum];
}
return;
}
dfs(k + 1,tot,sum);
dfs(k + 1,tot + 1,sum + 1LL*(d[k] + 1) * c[k]);
}
int main()
{
#ifdef YZY
freopen("yzy.txt","r",stdin);
#endif
for (i = 0; i < 4; i++) scanf("%d",&c[i]);
cin >> m;
f[0] = 1;
for (j = 0; j < 4; j++)
for (i = c[j]; i <= 100000; i++)
f[i] += f[i - c[j]];
while (m--)
{
for (i = 0; i < 4; i++) scanf("%d",&d[i]);
scanf("%d",&n);
ans = 0;
dfs(0,0,0);
ans += f[n];
printf("%lld\n",ans);
}
return 0;
}