[lnsyoj729/luoguP1450/HAOI2008]硬币购物

题意

给出一个长度为 4 的序列 c,给出 n 个询问,每个询问给出一个长度为 4 的序列 d 和 整数 s,要求构造出长度为 4 的序列 t,使得 s=i=14citi,且 (xR)(1x4),txdx),求 t 的方案数

sol

一眼多重背包问题,但无论使用哪种做法都无法在 1s 内解决,只好思考容斥。
(注:接下来,我们记 cntx 表示满足 x=i=14citi的方案数)
答案显然不是 cnts,因为存在序列 d 限制。考虑减掉对于 14 中的每个数 i,当 ti>di 时的方案数,即 cntsci(di+1)(因为需要保证 ti>di,因此先选出 di+1ci,再正常选择)。
此时多减了两个数多选的情况,由此,即可写出容斥式

cnt 数组也很好计算,事实上,它就是完全背包一维优化的 f 数组。

代码

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 100005;

int c[4], d[4];
int n, s;
long long f[N];

int p(int x){
    return 1 - x % 2 * 2;
}

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

int main(){
    scanf("%d%d%d%d%d", &c[0], &c[1], &c[2], &c[3], &n);

    init();

    while (n -- ){
        scanf("%d%d%d%d%d", &d[0], &d[1], &d[2], &d[3], &s);

        long long ans = 0;

        for (int s0 = 0; s0 < 16; s0 ++ ){
            int l = 0;
            long long sum = 0;
            for (int u = 0; u < 4; u ++ )
                if ((s0 >> u) & 1) l ++ , sum += (long long) c[u] * (d[u] + 1);
            
            if (s >= sum) ans += p(l) * f[s - sum];
        }

        printf("%lld\n", ans);
    }
}

蒟蒻犯的若至错误

  • init() 和 main() 中的下标起始位置不统一
posted @   是一只小蒟蒻呀  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示