[dp]最优除法

embedded/2024/12/21 10:59:49/

问题描述

请你通过若干次除法将一个数字 x x x 变得不超过 y y y

现在有很多个除数可以选择,给定一个长度为 n n n 的序列 b b b。表示除数 i i i 的花费是 b i b_i bi, 你可以用这个除数把 x x x 变为 x / i x / i x/i。每种除数可以使用无限次。

多组询问,每组询问输入两个数 x , y x, y x,y,表示需要使用若干次除法把 x x x 变得不超过 y y y,对于每一组询问你都要输出一个答案表示求最小花费,保证题目一定有解。

输入格式

输入包含 q + 2 q + 2 q+2 行。
第一行输入两个正整数 n , q n, q n,q
第二行输入 n n n 个正整数,第 i i i 个数表示 b i b_i bi。 接下来 q q q 行,每行两个正整数 x , y x, y x,y,如题意所示。

输出格式

输出 q q q 行。 每行输出一个数,表示对应询问的答案。

样例

样例输入1:

5 3 
4 3 2 2 4 
4 3 
1 4 
5 1

样例输出1:

2 
0 
2

数据范围

对于 20 % 20\% 20% 的数据, 1 ≤ n , q , x , y ≤ 1 0 2 1 \le n, q, x, y \le 10^2 1n,q,x,y102
对于 40 % 40\% 40% 的数据, 1 ≤ n , q , x , y ≤ 1 0 3 1 \le n, q, x, y \le 10^3 1n,q,x,y103
对于 100 % 100\% 100% 的数据, 1 ≤ n , q , x , y ≤ 1 0 5 1 \le n, q, x, y \le 10^5 1n,q,x,y105 1 ≤ b i ≤ 1 0 9 1 \le b_i \le 10^9 1bi109

题解

首先,我们考虑正着想,用 d p i dp_{i} dpi 表示到 i i i 的最小花费。
因此, d p i = d p x / k + a k dp_{i} = dp_{x / k} + a_k dpi=dpx/k+ak,复杂度为 O ( n 2 × T ) O(n^2 \times T) O(n2×T)
由于多组数据, x x x 不同,因此每次都要算一下 d p dp dp 数组,不能进行预处理。
也可以写记忆化搜索,比 dp 稍快,能得 50 50 50 分。

考虑反向思考,从 1 1 1 开始乘, d p i dp_{i} dpi 表示造成 i i i 点削减的最小花费。
初始化 d p i = min ⁡ ( d p j ) { 1 ≤ j ≤ n } dp_{i} = \min(dp_{j})\{1 \le j \le n\} dpi=min(dpj){1jn}
接下来完全背包预处理,结束时同样进行上面操作即可。

对于每次询问,只需找出 ⌊ x p ⌋ ≤ y \lfloor\frac{x}{p}\rfloor \le y pxy p p p 的最小值即可。
可以使用二分和直接计算。
二分单调性证明: d p i = min ⁡ ( d p j ) { 1 ≤ j ≤ n } dp_i = \min(dp_j)\{1 \le j \le n\} dpi=min(dpj){1jn},对于 d p i dp_i dpi d p i + 1 dp_{i + 1} dpi+1 d p i + 1 dp_{i + 1} dpi+1 一定小于等于 min ⁡ ( d p i + 1 , d p i ) \min(dp_{i + 1}, dp_i) min(dpi+1,dpi)

memset(a, 0x3f, sizeof(a));
输入
for(int i = n - 1; i >= 1; -- i){a[i] = min(a[i], a[i + 1]);
}
//dp
for(int i = 1; i <= 100000; ++ i){for(int j = 1; j <= 100000 / i; ++ j){a[i * j] = min(a[i * j], a[i] + a[j]);}
}
for(int i = 1e5 - 1; i >= 1; -- i){a[i] = min(a[i], a[i + 1]);
}
a[1] = 0;
while(q --){int x, y;scanf("%d %d", &x, &y);printf("%d\n", a[x / (y + 1) + 1]);
}

http://www.ppmy.cn/embedded/121770.html

相关文章

Oracle中MONTHS_BETWEEN()函数详解

文章目录 前言一、MONTHS_BETWEEN()的语法二、主要用途三、测试用例总结 前言 在Oracle数据库中&#xff0c;MONTHS_BETWEEN()函数可以用来计算两个日期之间的月份差。它返回一个浮点数&#xff0c;表示两个日期之间的整月数。 一、MONTHS_BETWEEN()的语法 MONTHS_BETWEEN(dat…

《RabbitMQ篇》基本概念介绍

MQ功能 解耦 MQ允许不同系统或组件之间松散耦合。发送者和接收者不需要直接连接&#xff0c;从而提高了系统的灵活性和可维护性。异步处理 使用MQ可以实现异步消息传递&#xff0c;发送者可以将消息放入队列后立即返回&#xff0c;不必等待接收者处理。这提高了系统的响应速度…

Qt 概述

1. Qlabel HelloWorld 程序 使用纯代码实现 // widget.cpp Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);// 给当前这个lable对象&#xff0c;指定一个父对象QLabel* label new QLabel(this);// C语言风格的字符串可以直接…

[数据集][目标检测]辣椒缺陷检测数据集VOC+YOLO格式695张5类别

重要说明&#xff1a;数据集图片里面都是一个辣椒&#xff0c;请仔细查看图片预览&#xff0c;确认符合要求下载 数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文…

Excel根据一个值匹配一行数据

根据一个值从一个表中匹配一行数据&#xff0c;例如从左边的表中找到指定姓名的所有行数据 使用VLOOKUP函数&#xff0c;参数&#xff1a; Lookup_value&#xff1a;需要搜索的值&#xff0c;单个值 Table_array&#xff1a;被搜索的区域&#xff0c;是个表 Col_index_num&…

双指针,平衡二叉树与最小生成树

1&#xff1a;直方图的水量 题目链接&#xff1a;面试题 17.21. 直方图的水量 - 力扣&#xff08;LeetCode&#xff09; 双指针 初始化&#xff1a;我们使用两个指针 left 和 right 分别指向数组的开始和结束。同时&#xff0c;我们记录下这两个位置的高度&#xff0c;即 max…

深度学习----------------------------编码器、解码器架构

目录 重新考察CNN重新考察RNN编码器-解码器架构总结编码器解码器架构编码器解码器合并编码器和解码器 重新考察CNN 编码器&#xff1a;将输入编码成中间表达形式&#xff08;特征&#xff09; 解码器&#xff1a;将中间表示解码成输出。 重新考察RNN 编码器&#xff1a;将文…

千益畅行,旅游创业新模式的创新与发展

旅游创业的时代背景与旅游卡的崛起&#xff0c;在当今快节奏的时代&#xff0c;旅行成为人们生活中的重要部分&#xff0c;随着科技发展和市场需求的变化&#xff0c;旅游创业项目中的旅游卡应运而生。 其中&#xff0c;“千益畅行” 旅游卡作为新兴力量&#xff0c;在共享经济…