P1450 [HAOI2008] 硬币购物

完全背包加上容斥,思想非常妙

#include <bits/stdc++.h>
#define for1(i,a,b) for (int i = a;i <= b;i ++) 
#define ll long long

const int maxn = 1e5+5;
const int inf = 99824353;
long long dp[maxn+10];
int c[10],d[10],T;
int sum;
ll ans;
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    for1(i,1,4)
		std::cin>>c[i];
    dp[0] = 1;//0的方案数:不取 
    for1(i,1,4)//完全背包 
		for1(j,c[i],maxn)
			dp[j] += dp[j-c[i]];
			
	std::cin>>T; 
    while (T--)
	{
		ans = 0;
        for1(i,1,4)
			std::cin>> d[i];
        std::cin>>sum;
        for1(i,0,15)//容斥 
		{
            ll ji = sum;
            int cnt = 0;
            
            for1(j,1,4)
				if ((i>>(j - 1)) & 1)
				{
					ji -= c[j] * (d[j] + 1);
					cnt^=1;
				}
            if (ji < 0) continue;
            if (!cnt) //单数个就加,双数个就减 
				ans += dp[ji];
			else 
				ans -= dp[ji];
        }
        std::cout<<ans<<'\n';
    }
    return 0;
}

posted @ 2023-02-16 21:14  yyx525jia  阅读(14)  评论(0)    收藏  举报