bzoj 1042 HAOI2008 硬币购物

这道题思路是在是神。

先dp出没有限制时候的方案数。

dp的时候注意 先循环 1..4 再循环 1..maxs 防止重复。边界是f[0] = 1。 这么基础的背包都忘记了=_=

接下来处理有重复的问题,容斥原理

    容斥原理说起来很简单,但有一些很神奇的应用,比如这道题。

最终的答案 = 没有限制的方案 - 其中一种超了限制的方案 + 其中两种超了限制的方案 - 三种超了限制的方案 + 四种超了限制的方案

ans = f[s] + f[s - c[i]*(d[i]+1)]  - ……  + f[s - c[1]*(d[1]+1)……]

为什么是 d[i]+1 呢?

至少用d[i]+1个,剩下的随意,又是不限制的方案数了。

上代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100010
using namespace std;

int c[5], n, d[5], s;
long long f[N] = {0};

void make_f()
{
    f[0] = 1;
    for (int j = 1; j <= 4; ++j)
        for (int i = c[j]; i <= N-10; ++i)
            f[i] += f[i-c[j]];
}

long long getans()
{
    long long ans = f[s];
    for (int i = 1; i <= 4; ++i)
        if (s - c[i]*(d[i]+1) >= 0)
            ans -= f[s - c[i]*(d[i]+1)];
    for (int i = 1; i <= 3; ++i)
        for (int j = i+1; j <= 4; ++j)
            if (s - c[i]*(d[i]+1) - c[j]*(d[j]+1) >= 0)
                ans += f[s - c[i]*(d[i]+1) - c[j]*(d[j]+1)];
    for (int i = 1; i <= 2; ++i)
        for (int j = i+1; j <= 3; ++j)
            for (int k = j+1; k <= 4; ++k)
                if (s - c[i]*(d[i]+1) - c[j]*(d[j]+1) - c[k]*(d[k]+1) >= 0)
                    ans -= f[s - c[i]*(d[i]+1) - c[j]*(d[j]+1) - c[k]*(d[k]+1)];
        if (s - c[1]*(d[1]+1) - c[2]*(d[2]+1) - c[3]*(d[3]+1) - c[4]*(d[4]+1) >= 0)
            ans += f[s - c[1]*(d[1]+1) - c[2]*(d[2]+1) - c[3]*(d[3]+1) - c[4]*(d[4]+1)];
    return ans;

}

int main()
{
    for (int i = 1; i <= 4; ++i) scanf("%d", &c[i]);
    make_f(); scanf("%d", &n);
    while (n--)
    {
        for (int i = 1; i <= 4; ++i) scanf("%d", &d[i]);
        scanf("%d", &s);
        printf("%I64d\n", getans());
    }
    return 0;
}
时间: 2024-10-05 02:33:56

bzoj 1042 HAOI2008 硬币购物的相关文章

bzoj 1042: [HAOI2008]硬币购物 dp+容斥原理

题目链接 1042: [HAOI2008]硬币购物 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1706  Solved: 985[Submit][Status][Discuss] Description 硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了tot次.每次带di枚ci硬币,买si的价值的东西.请问每次有多少种付款方法. Input 第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3

[BZOJ 1042] [HAOI2008] 硬币购物 【DP + 容斥】

题目链接:BZOJ - 1042 题目分析 首先 Orz Hzwer ,代码题解都是看的他的 blog. 这道题首先使用DP预处理,先求出,在不考虑每种硬币个数的限制的情况下,每个钱数有多少种拼凑方案. 为了避免重复的方案被转移,所以我们以硬币种类为第一层循环,这样阶段性的增加硬币. 一定要注意这个第一层循环要是硬币种类,并且初始 f[0] = 1. f[0] = 1; for (int i = 1; i <= 4; ++i) { for (int j = B[i]; j <= MaxS; +

BZOJ 1042: [HAOI2008]硬币购物(容斥原理)

http://www.lydsy.com/JudgeOnline/problem.php?id=1042 题意: 思路: 如果不考虑硬币个数的话,这就是一道完全完全背包的题目. 直接求的话行不通,于是这里要用容斥原理来做. 简单来说,ans=一种没超-一种硬币超+两种硬币超-三种硬币超+四种硬币超. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio>

BZOJ 1042 [HAOI2008]硬币购物 容斥原理

题意:链接 方法:容斥原理 解析:简单题,不掉坑都对不起我自己 这题很好想的一个容斥原理,因为一共只有四种硬币,我们不方便计算满足题中要求的方案数,但是从反向思考,我们需要做的就是减掉奇数个硬币用超额的情况,然后加上偶数个硬币用超额的情况就是最终的答案(当然状态是0000的时候看做是一个基准). 然后我没什么说的了,只是有一些细节需要注意下: 1.要用long long 2.完全背包千万不要傻到每次重新背,直接一次预处理就好,不过我为什么要重新背啊!(差了8s) 代码: #include <cs

bzoj 1042: [HAOI2008]硬币购物【容斥原理+dp】

当然是容斥啦. 用dp预处理出\( f[i] \),表示在\( i \)价格时不考虑限制的方案数,转移方程是\( f[i]+=f[i-c[j]] \),用状压枚举不满足的状态容斥一下即可. #include<iostream> #include<cstdio> using namespace std; const long long N=100005; long long c[10],T,d[10],s,f[N],ans; long long read() { long long

【BZOJ 1042】 [HAOI2008]硬币购物

1042: [HAOI2008]硬币购物 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 1175  Solved: 697 [Submit][Status] Description 硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了tot次.每次带di枚ci硬币,买si的价值的东西.请问每次有多少种付款方法. Input 第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,s Output

bzoj1042: [HAOI2008]硬币购物

好神的容斥原理 #include<cstdio> #include<cstring> #include<cctype> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define clr(x,c) memset(x,c,sizeof(x)) #define ll long long int

BZOJ-1042: [HAOI2008]硬币购物 (背包DP+容斥原理)

1042: [HAOI2008]硬币购物 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2888  Solved: 1777[Submit][Status][Discuss] Description 硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了tot次.每次带di枚ci硬币,买si的价值的东西.请问每次有多少种付款方法. Input 第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,

[HAOI2008]硬币购物

[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 to