bzoj1042 [HAOI2008]硬币购物

题目

我们先考虑最最朴素的dp,像什么第几种硬币用了几枚的方法数,显然单次O(n^4)的吧,跑到宇宙毁灭的优秀算法233。

如何优化呢?显然,如果硬币没有限制的话,就是一个十分简单的dp了

f[0]=1;
for(long long i=1;i<=4;i++)
    for(long long j=c[i];j<=N;j++)
        f[j]+=f[j-c[i]];

之后加上了数量限制,怎么办呢?

强行突破限制,上容斥定理,都没超出限制的方案数=无限制的-一个超的+两个超的。。。。

超的话,只需要超一个就可以了。

#include<bits/stdc++.h>
#define N 100000
using namespace std;
long long ans,f[N+1];
long long c[5],tot,d[5],s;
inline char nc()
{
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline long long read()
{
    long long x=0,b=1;
    char c=nc();
    for(;!(c<='9'&&c>='0');c=nc())if(c=='-')b=-1;
    for(;c<='9'&&c>='0';c=nc())x=x*10+c-'0';
    return x*b;
}
inline void init()
{
    f[0]=1;
    for(long long i=1;i<=4;i++)
        for(long long j=c[i];j<=N;j++)
            f[j]+=f[j-c[i]];
    return;
}
inline void write(long long x)
{
    char buf[25];
    long long len=0;
    if(!x)putchar('0');
    else
    {
        while(x)buf[++len]=x%10+'0',x/=10;
        for(long long i=len;i>=1;i--)putchar(buf[i]);
    }
    putchar('\n');
}
inline void get(long long pos,long long tmp,long long sum)
{
    if(sum<0)return;
    if(pos==5){
        long long b=(tmp&1)?-1:1;
        ans+=(long long)f[sum]*b;
        return;
    }
    get(pos+1,tmp+1,sum-(d[pos]+1)*c[pos]);
    get(pos+1,tmp,sum);
    return;
}
int main()
{
    //freopen("in.txt","r",stdin);
    for(long long i=1;i<=4;i++)c[i]=read();tot=read();
    init();
    for(long long i=1;i<=tot;i++)
    {
        for(long long j=1;j<=4;j++)d[j]=read();s=read();
        ans=0,get(1,0,s),write(ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值