解法一

首先不妨来思考一下怎样的一个付钱方案是最优的,假设需要支付 \(Y\) 元,第 \(a_i\) 种钱币支付了 \(s_i\) 张,那么必须有:\(s_i < \frac{a_{i + 1}}{a_i}\)。

否则一定可以通过调整减少钱币数量,那么若满足这个条件,付钱方案就是最优的了。

因为你付的钱和售货员找的钱当中一定存在一个 \(s_i = 0\),那么我们可以考虑将售货员找的钱取反就能恰好通过一个 \(s\) 序列表示一种可行的支付方案了。

于是问题转化为这样一个问题,求 \(s\) 序列的数量,满足:

\[\sum a_i \times s_i = X(-\frac{a_{i + 1}}{a_i} < s_i < \frac{a_{i + 1}}{a_i})
\]

同时通过这一条件,还可以推出 \(\forall i, \sum\limits_{j < i} a_j \times s_j < a_i\)。

因此,\(\forall i\) 应该要满足:\(|\sum\limits_{j \ge i} a_j \times s_j - X| < a_i\),注意到 \(a_i \mid \sum\limits_{j \ge i} a_j \times s_j\),因此这里的 \(\sum\limits_{j \ge i} a_j \times s_j\) 至多只有两种取值。

那么我们可以先计算出 \(\forall i, \sum\limits_{j \ge i} a_j \times s_j\) 的取值,然后就可以基于取值很少设计一个 \(dp\) 了。

不难发现可以令 \(f_{i, j}\) 表示 \(\sum\limits_{k \ge i} a_k \times s_k = j\) 时的方案数,转移时只需判断前后两个后缀之差这个位置是否能组成即可。

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; ++i)
#define dep(i, l, r) for (int i = r; i >= l; --i)
const int N = 50 + 5;
int n, X, ans, a[N], cnt[N], b[N][3], dp[N][3];
signed main () {
cin >> n >> X;
rep(i, 1, n) {
cin >> a[i];
int L = ceil(1.0 * (X - a[i] + 1) / a[i]), R = (X + a[i] - 1) / a[i];
rep(j, L, R) b[i][++cnt[i]] = j * a[i];
}
rep(i, 1, cnt[n]) dp[n][i] = 1;
dep(i, 1, n - 1)
rep(j, 1, cnt[i])
rep(k, 1, cnt[i + 1])
if(abs(b[i + 1][k] - b[i][j]) / a[i] < a[i + 1] / a[i])
dp[i][j] += dp[i + 1][k];
rep(i, 1, cnt[1]) ans += dp[1][i];
cout << ans;
return 0;
}

解法二

同样需要解法一当中付钱方案最优的思考,接下来你会发现这个东西本质上是一个类似进制的东西。

假设 \(Y, Z\) 分别为你付的钱,收获员找的钱,那么应该满足 \(X + Z = Y\)

将这个东西类似于十进制加法一样在这个类进制下考虑,你会发现 \(Z, Y\) 中在某一位必须至少有一个为 \(0\)。

若 \(X\) 这位也为 \(0\) 那么 \(Z\) 这一位只能填 \(0\),否则 \(Z\) 只能填一个使得这一位恰好进位的数。

那么此时本质上之前位填的数对当前位的影响只有进位或不进位两种,所以可以令 \(f_{i, 0 / 1}\) 表示考虑到第 \(i\) 位之前有没有进位的方案数即可。

关于(类)进制的一条重要性质:\(\forall i, \sum\limits_{j < i} a_j \times s_j < a_i\)

另外这种涉及某种进制在一些位取值不同的情况下的运算时,一定要有类似于十进制数加法运算的思考。

ABC182 F Valid payments的更多相关文章

  1. AtCoder Beginner Contest 182 F

    F - Valid payments 简化题意:有\(n\)种面值的货币,保证\(a[1]=1,且a[i+1]是a[i]的倍数\). 有一个价格为\(x\)元的商品,付款\(y\)元,找零\(y-x\ ...

  2. Angular2 表单

    1. 说明 表单是Web程序中的重要组成部分,构建良好以及实用的表单必须解决如下几个问题: (1). 如何跟踪及更新表单的数据状态 (2). 如何进行表单验证 (3). 如何显示表单验证信息 Angu ...

  3. R12 付款过程请求-功能和技术信息 (文档 ID 1537521.1)

    In this Document   Abstract   History   Details   _afrLoop=2234450430619177&id=1537521.1&dis ...

  4. 迈向angularjs2系列(7):表单

    目录 一:校验表单的使用 1.搭建脚手架 2.校验表单的使用 3.select下拉列表的用法 一: 校验表单的使用 对于CRUD型的应用,表单是必备组件. 1.搭建脚手架 git clone http ...

  5. Gluon炼丹(Kaggle 120种狗分类,迁移学习加双模型融合)

    这是在kaggle上的一个练习比赛,使用的是ImageNet数据集的子集. 注意,mxnet版本要高于0.12.1b2017112. 下载数据集. train.zip test.zip labels ...

  6. 『MXNet』第九弹_分类器以及迁移学习DEMO

    解压文件命令: with zipfile.ZipFile('../data/kaggle_cifar10/' + fin, 'r') as zin: zin.extractall('../data/k ...

  7. 【转载】 pytorch之添加BN

    原文地址: https://blog.csdn.net/weixin_40123108/article/details/83509838 ------------------------------- ...

  8. Swift5 语言参考(六) 声明

    一个声明引入了一个新的名称或构建到你的程序.例如,您使用声明来引入函数和方法,引入变量和常量,以及定义枚举,结构,类和协议类型.您还可以使用声明来扩展现有命名类型的行为,并将符号导入到其他地方声明的程 ...

  9. 学习笔记之IKM C++ 11

    https://github.com/haotang923/interview/tree/master/IKM Q1. If most of the calls to function foo() b ...

随机推荐

  1. CS5210|低成本HDMI转VGA方案|CS5210参数说明

    Capstone最新推出的一款HDMI转VGA音视频转接线或者转换器方案芯片CS5210. 其设计的优势在于内置晶振,外围电路器件较少设计简单,芯片封装集成度较高,方案BOM成本低,相比其他方案产品更 ...

  2. <数据结构>XDOJ323.判断有向图中是否有环

    问题与解答 问题描述 判断有向图中是否有环. 输入格式 输入数据第一行是一个正整数,表示n个有向图,其余数据分成n组,每组第一个为一个整数,表示图中的顶点个数n,顶点数不超过100,之后为有向图的邻接 ...

  3. JavaScript交互式网页设计 • 【第2章 JavaScript函数与事件】

    全部章节   >>>> 本章目录 2.1 JavaScript 自定义函数 2.1.1 函数的定义 2.1.2 函数的调用 2.1.3 函数的参数 2.1.4 函数的返回值 2 ...

  4. 访问局域网内其他主机的VMware虚拟机上的mysql数据库和redis缓存

    上一篇写了访问局域网内其他主机的虚拟机上的项目 ,现在说说访问局域网内其他主机的虚拟机上的数据库和缓存 博主使用的linux是Ubuntu16.04: 一.安装数据库和缓存 这里连接的数据库和缓存以m ...

  5. SpringBoot 之 扩展 SpringMVC

    增加自定义视图解析器: # src/main/java/com/wu/config/MyMvcConfig.java @Configuration // 标注这个类是一个配置类 public clas ...

  6. html 基础 audio和video的基础使用

    基础标签 文本格式化标签: 标签 说明 <b></b>/<strong></strong> 加粗 <u></u>/<ins ...

  7. 通过 v-once 创建低开销的静态组件

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <script s ...

  8. Android系统编程入门系列之硬件交互——通信硬件USB

    在硬件交互的首篇对设备硬件的分类中,互联通信系列硬件主要用来与其他设备进行数据交互.从本文开始,将重点介绍该系列相关硬件. 互联通信系列硬件 根据硬件的可通信距离,由近及远分为USB.NFC.蓝牙.W ...

  9. Linux下Tomcat启动、停止、重新启动

    在Linux系统下,重启Tomcat使用命令操作的! 1.首先,进入Tomcat下的bin目录,${CATALINA_HOME}代表tomcat的安装路径 进入Tomcat安装目录: cd ${CAT ...

  10. Go语言发邮件

    发送邮件是实际业务中经常会用到的一个功能,而在Go语言中实现发送邮件的库也有很多,这篇文章将介绍go语言中如何发邮件. 1. 登录QQ邮箱,选择账户,开启POP3/SMTP服务和IMAP/SMTP服务 ...