组合数学+费用背包+刷表,G2 - Playlist for Polycarp (hard version)

news2024/9/20 8:04:04

目录

一、题目

1、题目描述

2、输入输出

2.1输入

2.2输出

3、原题链接

二、解题报告

1、思路分析

2、复杂度

3、代码详解


一、题目

1、题目描述

2、输入输出

2.1输入

2.2输出

3、原题链接

G2 - Playlist for Polycarp (hard version)

二、解题报告

1、思路分析

一眼dp,但是这个dp思路和代码都不太好想

首先是涉及到组合数学的分配问题

方案数怎么求?

既涉及到了相邻的顺序,又涉及到了容量/费用

我们可以单独考虑然后相乘:

f(i, j, k, x) 为 选取 i 个类型1,j个 类型2,k 个类型3,并且以类型x结尾,且无相同相邻项的方案数

这个dp可太简单了,O(1)转移,O(N^3 * 3)的方案数,很好搞定

再考虑 g(i, j, k, t) 即 选 i 个类型1,j个 类型2,k 个类型3,总费用为t(费用指的是时间和)的方案数

这是个费用背包问题,我们直接求是O(N ^ 4 T),太大了

考虑转换一下,g(j, k, p) 为 j个 类型2,k 个类型3 总费用为t方案数,h(i, T - p)为i个类型1,总费用为t的方案数,乘法原理二者相乘可得

然后 (f(i, j, k, 0) + f(i, j, k, 1) f(i, j, k, 2)) * g(j, k, p) * h(i, T - p) * fac(i) * fac(j) * fac(k) 就是一组方案数

什么意思?

f 确定了每个类型放的位置,然后每个类型的每个物品是不同的,这就是一个多重集排列问题

然后 h 和 t 又确定了选取哪些类型1、2、3,再根据乘法原理乘一块就是答案

2、复杂度

时间复杂度: O(N^3 T)空间复杂度:O(N^ T)

3、代码详解

 ​
#include <bits/stdc++.h>
#define sc scanf
using i64 = long long;
using PII = std::pair<int, int>;
constexpr int N = 55, M = 2505, P = 1'000'000'007;

void add(int& x, int y) { x += y, (x >= P) && (x -= P); }
int fac[N], f[N][N / 2][N / 3][3], g[N / 2][N / 3][M], h[N][M];

void solve() {
    int n, T;
    std::cin >> n >> T;

    fac[0] = 1;
    for (int i = 1; i <= n; ++ i) fac[i] = 1LL * i * fac[i - 1] % P;

    std::vector<int> a, b, c;
    std::vector<std::array<int, 3>> cnt(n);
    for (int i = 0, t, g; i < n; ++ i) {
        std::cin >> t >> g;
        if (g == 1) a.push_back(t);
        if (g == 2) b.push_back(t);
        if (g == 3) c.push_back(t);
    }

    if (a.size() < b.size())
        std::swap(a, b);
    if (a.size() < c.size()) 
        std::swap(a, c);
    if (b.size() < c.size())
        std::swap(b, c);

    int A = a.size(), B = b.size(), C = c.size();
    // 求费用背包
    g[0][0][0] = 1;
    for (int i = 0; i < B; ++ i) 
        for (int j = i; ~j; -- j) 
            for (int p = T - b[i]; p >= 0; -- p)
                add(g[j + 1][0][p + b[i]], g[j][0][p]);

    for (int i = 0; i < C; ++ i)
        for (int j = B; j >= 0; -- j)
            for (int k = i; k >= 0; -- k)
                for (int p = T - c[i]; p >= 0; -- p) 
                    add(g[j][k + 1][p + c[i]], g[j][k][p]);

    h[0][0] = 1;
    for (int i = 0; i < A; ++ i) 
        for (int j = i; ~j; -- j) 
            for (int p = T - a[i]; p >= 0; -- p) 
                add(h[j + 1][p + a[i]], h[j][p]);


    // 刷表
    f[1][0][0][0] = f[0][1][0][1] = f[0][0][1][2] = 1;
    for (int i = 0; i <= A; ++ i)
        for (int j = 0; j <= B; ++ j)
            for (int k = 0; k <= C; ++ k) {
                for (int x = 0, v; x < 3; ++ x) {
                    if (v = f[i][j][k][x]) {
                        if (x) add(f[i + 1][j][k][0], v);
                        if (x ^ 1) add(f[i][j + 1][k][1], v);
                        if (x ^ 2) add(f[i][j][k + 1][2], v);
                    }
                }
                add(f[i][j][k][0], f[i][j][k][1]);
                add(f[i][j][k][0], f[i][j][k][2]);
                f[i][j][k][0] = 1LL * f[i][j][k][0] * fac[i] % P * fac[j] % P * fac[k] % P;
            }

    int res = 0;
    for (int j = 0; j <= B; ++ j)
        for (int k = 0; k <= C; ++ k)
            for (int p = 0; p <= T; ++ p)
                if (g[j][k][p])
                    for (int i = 0; i <= A; ++ i)
                        if (h[i][T - p])
                            add(res, 1LL * f[i][j][k][0] * g[j][k][p] % P * h[i][T - p] % P);
    std::cout << res;
}

int main() {
    #ifdef DEBUG
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    #endif
    std::ios::sync_with_stdio(false), std::cin.tie(nullptr), std::cout.tie(nullptr);
    int _ = 1;
    // std::cin >> _;
    while (_ --)
        solve();
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux驱动开发-05APP和驱动的交互方式

一、传输数据 APP和驱动: copy_to_usercopy_from_user驱动和硬件: 各个子系统的函数通过ioremap映射寄存器地址后,直接访问寄存器二、APP使用驱动的四种方式 驱动程序:提供能力,不提供策略 非阻塞(查询)(应用程序访问底层驱动时(read、write时),驱动没有数据不等待,…

【Vue】深入理解 `v-model` 指令:实现数据双向绑定的终极指南

文章目录 一、v-model 指令概述二、v-model 的基本用法1. 绑定输入框的值2. 绑定多行文本框的值3. 绑定复选框4. 绑定单选框5. 绑定选择框 三、v-model 的工作原理四、v-model 的高级用法1. 自定义组件中的 v-model模板部分 (<template>)脚本部分 (<script>) 2. 多…

vue项目源码调试方法 ,chrome调试控制台工作区使用,利用chrome控制台调试vue项目源码的方法 图解

我们在开发vue项目的时候&#xff0c;项目开始后的第一件事情应该就是准备调试工作了&#xff0c;Chrome调试控制台就给我们提供了这样的一个方便的调试工作区。方法为&#xff0c;在Chrome浏览器里面打开你要调试的页面&#xff0c;然后打开调试控制台&#xff0c;如下&#x…

基于STC8H4K64TL单片机的触摸功能和数码管驱动功能实现一个触摸按键单击长按都增加数值另一个触摸按键单击长按都减少数值应用

基于STC8H4K64TL单片机的触摸功能和数码管驱动功能实现一个触摸按键单击长按都增加数值另一个触摸按键单击长按都减少数值应用 STC8H4K64TL单片机介绍STC8H4K64TL单片机管脚图(48个引脚)STC8H4K64TL单片机串口仿真与串口通信STC8H4K64TL单片机管脚图(32个引脚)STC8H4K64TL单…

【Linux】汇总TCP网络连接状态命令

输入命令&#xff1a; netstat -na | awk /^tcp/ {S[$NF]} END {for(a in S) print a, S[a]} 显示&#xff1a; 让我们逐步解析这个命令&#xff1a; netstat -na: netstat 是一个用于显示网络连接、路由表、接口统计等信息的命令。 -n 选项表示输出地址和端口以数字格式显示…

ACCL+: an FPGA-Based Collective Engine for Distributed Applications——论文泛读

OSDI 2024 Paper 论文阅读笔记整理 问题 FPGA在云部署中越来越普遍[16,81]&#xff0c;如智能NIC[29,35,64,67103]、流处理器[31,32,55,68]和分布式加速器[15,41,61,65,86,93115]。可以使用FPGA到FPGA的直接通信来构建高效的分布式系统。然而&#xff0c;使用FPGA设计分布式应…

通过 EMR Serverless Spark 提交 PySpark 流任务

在大数据快速发展的时代&#xff0c;流式处理技术对于实时数据分析至关重要。EMR Serverless Spark提供了一个强大而可扩展的平台&#xff0c;它不仅简化了实时数据处理流程&#xff0c;还免去了服务器管理的烦恼&#xff0c;提升了效率。本文将指导您使用EMR Serverless Spark…

python爬虫获取网易云音乐评论歌词以及歌曲地址

python爬虫获取网易云音乐评论歌词以及歌曲地址 一.寻找数据接口二.对负载分析三.寻找参数加密过程1.首先找到评论的请求包并找到发起程序2.寻找js加密的代码 四.扣取js的加密源码1.加密函数参数分析①.JSON.stringify(i0x)②bse6Y(["流泪", "强"])③bse6Y…

Linux--Socket套接字编程

Socket编程 Socket编程是一种在网络中不同计算机之间实现数据交换的编程方式。它允许程序创建网络连接&#xff0c;并通过这些连接来发送和接收数据。Socket编程是网络编程的基础&#xff0c;广泛应用于客户端-服务器&#xff08;C/S&#xff09;架构中。 要实现双方通信&…

【扩散模型(六)】Stable Diffusion 3 diffusers 源码详解1-推理代码-文本处理部分

系列文章目录 【扩散模型&#xff08;一&#xff09;】中介绍了 Stable Diffusion 可以被理解为重建分支&#xff08;reconstruction branch&#xff09;和条件分支&#xff08;condition branch&#xff09;【扩散模型&#xff08;二&#xff09;】IP-Adapter 从条件分支的视…

基于python的去除图像内部填充

1 代码功能 该代码实现了一个图像处理的功能&#xff0c;具体来说是去除图像内部填充&#xff08;或更准确地说&#xff0c;是提取并显示图像中轮廓的外围区域&#xff0c;而忽略内部填充&#xff09;。以下是该功能的详细步骤&#xff1a; 读取图像&#xff1a;使用cv2.imread…

Hadoop-38 Redis 高并发下的分布式缓存 Redis简介 缓存场景 读写模式 旁路模式 穿透模式 缓存模式 基本概念等

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; HadoopHDFSMapReduceHiveFlumeSqoopZookeeperHBaseRedis 章节内容 上一节我们完成了&#xff1a; HBase …

机器学习-18-统计学与机器学习中回归的区别以及统计学基础知识

参考通透!一万字的统计学知识大梳理 参考3万字长文!手把手教你学会用Python实现统计学 参考统计学的回归和机器学习中的回归有什么差别? 1 研究对象 一维:就是当前摆在我们面前的“一组”,“一批数据。这里我们会用到统计学的知识去研究这类对象。 二维:就是研究某个“事…

【系统架构设计】数据库系统(三)

数据库系统&#xff08;三&#xff09; 数据库模式与范式数据库设计备份与恢复分布式数据库系统分布式数据库的概念特点分类目标 分布式数据库的架构分布式数据库系统与并行数据库系统 数据仓库数据挖掘NoSQL大数据 数据库模式与范式 数据库设计 备份与恢复 分布式数据库系统…

生活中生智慧

【 圣人多过 小人无过 】 觉得自己做得不够才能做得更好&#xff0c;互相成全&#xff1b;反求诸己是致良知的第一步&#xff1b;有苦难才能超越自己&#xff0c;开胸怀和智慧&#xff1b;不浪费任何一次困苦&#xff0c;危机中寻找智慧&#xff0c;成长自己。 把困苦当作当下…

自动驾驶三维车道线检测系列—LATR: 3D Lane Detection from Monocular Images with Transformer

文章目录 1. 概述2. 背景介绍3. 方法3.1 整体结构3.2 车道感知查询生成器3.3 动态3D地面位置嵌入3.4 预测头和损失 4. 实验评测4.1 数据集和评估指标4.2 实验设置4.3 主要结果 5. 讨论和总结 1. 概述 3D 车道线检测是自动驾驶中的一个基础但具有挑战性的任务。最近的进展主要依…

【NetTopologySuite类库】GeometryFixer几何自动修复,解决几何自相交等问题

介绍 NetTopologySuite 2.x 提供了GeometryFixer类&#xff0c;该类能够将几何体修复为有效几何体&#xff0c;同时尽可能保留输入的形状和位置。几何的IsValid属性&#xff0c;反映了几何是否是有效的。 输入的几何图形始终会被处理&#xff0c;因此即使是有效的输入也可能会…

特征工程方法总结

方法有以下这些 首先看数据有没有重复值、缺失值情况 离散&#xff1a;独热 连续变量&#xff1a;离散化&#xff08;也成为分箱&#xff09; 作用&#xff1a;1.消除异常值影响 2.引入非线性因素&#xff0c;提升模型表现能力 3.缺点是会损失一些信息 怎么分&#xff1a;…

pdf太大了怎么变小 pdf太大了如何变小一点

在数字化时代&#xff0c;pdf文件已成为工作与学习的重要工具。然而&#xff0c;有时我们可能会遇到pdf文件过大的问题&#xff0c;这会导致传输困难或者存储不便。别担心&#xff0c;下面我将为你介绍一些实用的技巧和工具&#xff0c;帮助你轻松减小pdf文件的大小。 方法一、…

docker的学习(一):docker的基本概念和命令

简介 docker的学习&#xff0c;基本概念&#xff0c;以及镜像命令和容器命令的使用 docker docker的基本概念 一次镜像&#xff0c;处处运行。 在部署程序的过程中&#xff0c;往往是很繁琐的&#xff0c;要保证运行的环境&#xff0c;软件的版本&#xff0c;配置文件&…