首页 > 其他分享 >P7224 [RC-04] 子集积 (背包 dp + 复杂度优化)

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

时间:2024-07-06 21:57:55浏览次数:7  
标签:std P7224 04 int 复杂度 i64 dp mod

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_back

using 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;
}

标签:std,P7224,04,int,复杂度,i64,dp,mod
From: https://www.cnblogs.com/FireRaku/p/18287984

相关文章

  • C++算法实践04-寻找两个正序数组的中位数
    一、题目:给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。算法的时间复杂度应该为 O(log(m+n)) 。示例1:输入:nums1=[1,3],nums2=[2]输出:2.00000解释:合并数组=[1,2,3],中位数2示例2:输入:nu......
  • Ubuntu 22.04.4 LTS 安装 php apache LAMP 环境nginx
    1安装php-fpmaptupdateapt-getinstallphp-fpm#配置php-fpm服务启动systemctlenablephp8.1-fpmsystemctlstartphp8.1-fpm#查看服务systemctlstatusphp8.1-fpm#查看版本root@iZbp1g7fmjea77vsqc5hmmZ:~#php-vPHP8.1.2-1ubuntu2.18(cli)(built:......
  • L1-046 整除光棍(模拟除法)
    这里所谓的“光棍”,并不是指单身汪啦~说的是全部由1组成的数字,比如1、11、111、1111等。传说任何一个光棍都能被一个不以5结尾的奇数整除。比如,111111就可以被13整除。现在,你的程序要读入一个整数x,这个整数一定是奇数并且不以5结尾。然后,经过计算,输出两个数字:第一个数字s,表示......
  • L1-048 矩阵A乘以B
    给定两个矩阵A和B,要求你计算它们的乘积矩阵AB。需要注意的是,只有规模匹配的矩阵才可以相乘。即若A有Ra​行、Ca​列,B有Rb​行、Cb​列,则只有Ca​与Rb​相等时,两个矩阵才能相乘。输入格式:输入先后给出两个矩阵A和B。对于每个矩阵,首先在一行中给出其行数R和列数C,随后R行,每行给......
  • 读人工智能全传04NP完全问题
    1. 问题解决与搜索1.1. 解决问题的能力无疑是区分人类和其他动物的关键能力之一1.1.1. 解决问题是需要智慧的1.2. 汉诺塔1.2.1. 对于三个金环而言1.2.1.1. 你不可能找到少于7次的解决方案了1.2.2. 最初,我们只能选择移动最小的金环,只有将它移动到中间或者最右边的柱......
  • 07_04_暑期个人赛1
    C.Caninepoetry时间:2024-07-05原题:GoodBye2020C.Caninepoetry题意对于一个字符串\(s\),可以对任一字符变为\(*\)号,使所有子串不为回文串,即可将\(babba\)变为\(ba*ba\)使字符串内不存在回文串数据范围:\(|s|\le1e5\)思路对于某回文字符串,如果是长度为奇数,那......
  • P10449 费解的开关
    费解的开关题目描述你玩过“拉灯”游戏吗?\(25\)盏灯排成一个\(5\times5\)的方形。每一个灯都有一个开关,游戏者可以改变它的状态。每一步,游戏者可以改变某一个灯的状态。游戏者改变一个灯的状态会产生连锁反应:和这个灯上下左右相邻的灯也要相应地改变其状态。我们用数......
  • NO.04 Altium Designer组件参数类型
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档@TOCAltiumDesigner组件参数类型前言○由于“BOM、ActiveBOM或Draftsman必须与设计中的组件一致”因此无法直接进行删除BOM、ActiveBOM或Draftsman“其中一项;○不过可以通过设置组件“参数”类型......
  • 代码随想录算法训练营第十五天|110.平衡二叉树、257.二叉树的所有路径、404.左叶子之
    110平衡二叉树1classSolution{2public:3intGetHeight(TreeNode*root){4if(!root){5return0;6}7intleftHeight=GetHeight(root->left);8if(leftHeight==-1)ret......
  • Windows中启用Ubuntu22.04(WSL2,SSH)
    场景需要使用Ubuntu系统,需要使用显卡。wsl2不支持桌面显示,需安装远程桌面。安装需要先启用“适用于Linux的Windows子系统”可选功能,然后才能在Windows上安装Linux分发。以管理员身份打开PowerShell并运行:dism.exe/online/enable-feature/featurename:Microsoft-Windo......