[HAOI2008]硬币购物 [动态规划 完全背包][容斥]

P1450 [HAOI2008]硬币购物 

第一反应 多重背包 wodema 我准备好我的单调队列优化了 emmmm1k次???怎么搞????

瓜想20min 难道我真的无法自主做出一道题吗???是的呢
先考虑完全背包 然后根据dalao们说的 就像区间相减一样 emmm所以用f[money]-f[money-c[i]*(d[i]+1)]

这个原理有点点像前天做的消失之物  但是这个要用到容斥 容斥我又双叒叕没有系统搞过

欧阳说下面这个搜索版的要好理解一点  这个思想真的好巧妙!!!!

容斥大概是 求A,B,C,D....集合的面积 即A+B+C+...-A∩B-A∩C-B∩C-...+A∩B∩C+B∩C∩D...     大概这样推下去

最后注意开long long

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define ll long long
#define rg register
const int N=200+5,M=100000+5,inf=0x3f3f3f3f,P=99999997;
ll ans,T,m,a[5],d[5],f[M];
template <class t>void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}

void dfs(int nw,int mon,int fla){
    if(mon<0) return;
    if(nw>4) {ans+=f[mon]*fla;return;}
    dfs(nw+1,mon,fla);
    dfs(nw+1,mon-a[nw]*(d[nw]+1),-fla);
}

int main(){
//    freopen("in.txt","r",stdin);
    f[0]=1;
    for(int i=1;i<=4;++i){
        rd(a[i]);
        for(int v=a[i];v<M;++v) f[v]+=f[v-a[i]];
    }
    rd(T);
    while(T--){
        for(int i=1;i<=4;++i) rd(d[i]);
        rd(m);
        ans=0;
        dfs(1,m,1);
        printf("%lld
",ans);
    }
    return 0;
}
 
原文地址:https://www.cnblogs.com/lxyyyy/p/11180994.html