P7224 [RC-04] 子集积 (背包 dp + 复杂度优化)

news/2024/10/5 15:39:22/文章来源:https://www.cnblogs.com/FireRaku/p/18287984

P7224 [RC-04] 子集积

背包 dp + 复杂度优化

考虑 dp。容易想到背包 dp,设 \(f_{i,j}\) 表示考虑了前 \(i\) 个,当前乘积为 \(j\) 的方案数。枚举 \(a_i\) 的倍数转移。

复杂度 \(O(\sum\limits_{i=1}^n\frac{m}{a_i})\)。如果 \(a_i\) 互不相同,那么近似于 \(O(m\ln m)\)

如果还想要这样的复杂度,可以考虑相同的部分能不能同时处理。假设现在 \(a_i\)\(k\) 个,那么会组成 \(k\) 个不同的 \(a_i\) 的乘积(如 \(a_i\)\(a_i^2\)\(a_i^k\))。将这 \(k\) 个数放入背包的物品中,对于物品 \(a_i^j\),有 \(C(k,j)\) 的系数,每次转移同样是 \(\frac{m}{a_i^j}\) 的复杂度。

那么从原来每个相同的 \(a_i\) 都是 \(O(\frac{m}{a_i})\) 的复杂度,到现在所有相同的 \(a_i\) 总复杂度\(O(\sum\limits_{j=1}^k\frac{m}{a_{i}^j})\),由于下面是指数增长,所以近似于 \(O(\frac{m}{a_i})\)

需要注意的是,对于 \(a_i=1\) 的部分需要单独处理,最后将每个状态 \(f_i\times 2^{cnt_1}\) 即可。

复杂度 \(O(m\ln m)\)

#include <bits/stdc++.h>
#define pii std::pair<int, int>
#define mk std::make_pair
#define fi first
#define se second
#define pb push_backusing i64 = long long;
using ull = unsigned long long;
const i64 iinf = 0x3f3f3f3f, linf = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10, mod = 998244353;
int n, m, cnt[N];
i64 fac[N], inv[N], a[N], f[N];
i64 qpow(i64 a, i64 b) {i64 ret = 1;while(b) {if(b & 1) ret = ret * a % mod;a = a * a % mod;b >>= 1;}return ret;
}
void init() {fac[0] = 1;for(int i = 1; i <= n; i++) fac[i] = fac[i - 1] * i % mod;inv[n] = qpow(fac[n], mod - 2);for(int i = n - 1; i >= 0; i--) inv[i] = inv[i + 1] * (i + 1) % mod;
}
i64 C(i64 n, i64 m) {if(n < m) return 0;return fac[n] * inv[m] % mod * inv[n - m] % mod; 
}
int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);std::cin >> n >> m;init();i64 ans = qpow(2, n);for(int i = 1; i <= n; i++) {std::cin >> a[i];cnt[a[i]]++;}std::sort(a + 1, a + n + 1);n = std::unique(a + 1, a + n + 1) - a - 1;f[1] = 1;for(int i = 1; i <= n; i++) {if(a[i] == 1) continue;i64 val = 1;for(int j = m / a[i]; j >= 1; j--) {val = 1;for(int k = 1; k <= cnt[a[i]]; k++) {val *= a[i];if(j * val > m) break;f[j * val] = (f[j * val] + f[j] * C(cnt[a[i]], k) % mod) % mod;}}}i64 pw = qpow(2, cnt[1]);for(int i = 1; i <= m; i++) {ans = (ans - f[i] * pw % mod + mod) % mod;}std::cout << ans << "\n";return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/739550.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

(9)逻辑综合添加约束(时序、DRC)

一、前言dc综合是一个不断迭代的过程,如果设计的RTL代码不满足时序约束的需求,则需要重新进行修改,然后再去综合,一直迭代到时序满足需求。 二、面积约束面积约束指令:set_max_area 100面积约束的定义有三种,一种指的是两输入与非门的个数,一种是晶体管的个数,第三种是…

深度解析 Raft 分布式一致性协议

深度解析 Raft 分布式一致性协议本文参考转载至:浅谈 Raft 分布式一致性协议|图解 Raft - 白泽来了 - 博客园 (cnblogs.com) 深度解析 Raft 分布式一致性协议 - 掘金 (juejin.cn) raft-zh_cn/raft-zh_cn.md at master maemual/raft-zh_cn (github.com)本篇文章将模拟一个KV数…

nacos学习笔记之服务发现中心

一.什么是服务发现 在微服务中,服务的消费方需要调用服务的生产方,这样服务的消费方就需要知道服务的消费方的网络地址(ip+端口号)。 二、流程上图中服务实例本身并不记录服务生产方的网络地址,所有服务实例内部都会包含服务发现客户端(例如spring cloud中的ribbon)。 (…

第一次学习Java的碎碎念

2024年夏新的学习开始了; 今天做了什么? 在B站上收藏了黑马程序员学习Java的教学视频,观看了几篇入门教程,暂时学会了如何打开CMD,以及几个常见的CMD命令,例如盘符名称:、dir、cd目录、cd..、cls、exit等等,做了一个练习(利用cmd打开qq),学会了如何把应用程序的路径…

测试标题

测试摘要\[a /ge b /eq c \]

Java反射与Fastjson的危险反序列化

Preface 在前文中,我们介绍了 Java 的基础语法和特性和 fastjson 的基础用法,本文我们将深入学习fastjson的危险反序列化以及预期相关的 Java 概念。 什么是Java反射? 在前文中,我们有一行代码 Computer macBookPro = JSON.parseObject(preReceive,Computer.class); 这行代…

Win10双屏设置 之 鼠标不能从中间划过 问题解决

Win10双屏设置 之 鼠标不能从中间划过解决-百度经验 (baidu.com)

比赛获奖的武林秘籍:03 好的创意选取-获得国奖的最必要前提

本文主要介绍了大学生电子计算机类比赛和创新创业类比赛创意选取的重要性,并列举了好的创意选取和坏的创意选取的例子,同时说明了好的创意选取具有哪些特点,同时对常见的创意选取途径与来源进行了基本介绍。比赛获奖的武林秘籍:03 好的创意选取-获得国奖的最必要前提 摘要 …

阶段测试

Sre网络班阶段测试 一:用sed 命令修改/etc/fstab文件,删除文件中的空行,注释行,并保留文件备份(7分) 答案写这里:二: 用 find 命令查找出 /var/ 目录中大于1M且以db结尾的文件(7分) 答案写这里:三: 先判断当前主机是否安装了nginx包,如果没安装,则执行命令安装,…

时间序列分析专题——利用SPSS专家建模器进行建模

SPSS的专家建模器可以自动识别数据,给出最适合的模型,本章通过三个例题介绍如何使用SPSS实现时间序列分析。由于本人对时间序列分析的理解尚浅,做出模型后在论文上的呈现形式需要取查阅资料,以便更好地在论文上呈现 在此之前,我们还需要了解时间序列分析的一些基础的名词 …

如何在ubuntu上设置清华源

如何在ubuntu上设置清华源 apt介绍 apt(Advanced Packaging Tool)是一个在 Debian 和 Ubuntu 中的 Shell 前端软件包管理器。 apt 命令提供了查找、安装、升级、删除某一个、一组甚至全部软件包的命令,而且命令简洁而又好记。 apt 命令执行需要超级管理员权限(root)。 操作 …