题目描述

  有\(n\)种面值不同的硬币,每种有无限个,且任意两个\((x,y)\)要么\(x\)是\(y\)的倍数,要么\(y\)是\(x\)的倍数。

  你要取\(m\)元钱,问你有多少种不同的取法。

  \(n\leq 50,m\leq {10}^{18}\)

题解

  假设面值为\(a_1,a_2,\ldots,a_n\)

  先把所有硬币按面值从小到大排序。

  那么考虑从小到大取钱。

  如果前面\(i\)种面值已经取完了,那么取的钱数\(\bmod\)\(a_{i+1}\)已经确定了。

  有这么一个DP:设\(f_i(x)\)为取完了前面\(i\)种面值的硬币,取的钱数为\(xa_i+m\bmod a_i\)的方案数。

  转移:枚举\(i\)这种硬币用了多少个(或者说剩下了多少个):

\[\begin{align}
f_i(x)&=\sum_{j=0}^x f_{i-1}(\frac{ja_i+m\bmod a_i}{a_{i-1}})\\
&=\sum_{j=0}^x f_{i-1}(bj+c)\\
\end{align}
\]

  我们很容易发现\(f_i(x)\)是一个\(i\)次函数。

  那么只需要求\(f_i(0)\ldots f_i(i)\)就可以了。

  每次可以通过线性插值求出。

  时间复杂度:\(O(n^3)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int p=998244353;
ll fp(ll a,ll b){ll s=1;for(;b;b>>=1,a=a*a%p)if(b&1)s=s*a%p;return s;}
int f[60][60];
int ifac[60];
int inv[60];
int pp[60];
int *pre=pp+1;
int suf[60];
ll a[60];
int n;
ll m;
int c[60];
int gao(int id,ll x)
{
if(x<=id)
return f[id][x];
x%=p;
pre[-1]=1;
for(int i=0;i<=id;i++)
pre[i]=ll(x-i)*pre[i-1]%p;
suf[id+1]=1;
for(int i=id;i>=0;i--)
suf[i]=ll(x-i)*suf[i+1]%p;
ll s=0;
for(int i=0;i<=id;i++)
s+=(ll)f[id][i]*pre[i-1]%p*suf[i+1]%p*ifac[i]%p*ifac[id-i]%p*((id-i)&1?-1:1);
return s%p;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
scanf("%d%lld",&n,&m);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
ifac[0]=ifac[1]=inv[1]=1;
for(int i=2;i<=n;i++)
{
inv[i]=(ll)-p/i*inv[p%i]%p;
ifac[i]=(ll)ifac[i-1]*inv[i]%p;
}
f[1][0]=1;
f[1][1]=1;
for(int i=2;i<=n;i++)
for(int j=0;j<=i;j++)
f[i][j]=(f[i][j-1]+gao(i-1,(j*a[i]+m%a[i])/a[i-1]))%p;
int ans=gao(n,m/a[n]);
ans=(ans+p)%p;
printf("%lld\n",ans);
return 0;
}

【XSY2759】coin DP 线性插值的更多相关文章

  1. POJ1742 Coin [DP补完计划]

    题目传送门 Coins Time Limit: 3000MS   Memory Limit: 30000K Total Submissions: 41707   Accepted: 14125 Des ...

  2. [hdu 1398]简单dp

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1398 看到网上的题解都是说母函数……为什么我觉得就是一个dp就好了,dp[i][j]表示只用前i种硬币 ...

  3. 解题:USACO13NOV No Change

    题面 在朴素中透着一点新意的状压DP 一个很暴力的思路是枚举位置,状态和硬币,每次二分出向前最多能买到哪里,复杂度爆炸($O(2^knklog$ $n)$) 考虑优化,不妨先预处理一下$goal[i] ...

  4. Leetcode 322.零钱兑换

    零钱兑换 给定不同面额的硬币 coins 和一个总金额 amount.编写一个函数来计算可以凑成总金额所需的最少的硬币个数.如果没有任何一种硬币组合能组成总金额,返回 -1. 示例 1: 输入: co ...

  5. Java实现 LeetCode 518 零钱兑换 II

    518. 零钱兑换 II 给定不同面额的硬币和一个总金额.写出函数来计算可以凑成总金额的硬币组合数.假设每一种面额的硬币有无限个. 示例 1: 输入: amount = 5, coins = [1, ...

  6. UVA 674 Coin Change (DP)

    Suppose there are 5 types of coins: 50-cent, 25-cent, 10-cent, 5-cent, and 1-cent. We want to make c ...

  7. UVA 674 Coin Change 换硬币 经典dp入门题

    题意:有1,5,10,25,50五种硬币,给出一个数字,问又几种凑钱的方式能凑出这个数. 经典的dp题...可以递推也可以记忆化搜索... 我个人比较喜欢记忆化搜索,递推不是很熟练. 记忆化搜索:很白 ...

  8. UVA 674 Coin Change(dp)

    UVA 674  Coin Change  解题报告 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=87730#problem/ ...

  9. [HDOJ]Coin Change(DP)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=2069 题意 有面值1,5,10,25,50的硬币数枚,对于输入的面值n,输出可凑成面值n(且限制总硬笔 ...

随机推荐

  1. python四:函数练习--小白博客

    为什么要有函数?函数式编程定义一次,多出调用函数在一定程度上可以理解为变量函数的内存地址加上()就是调用函数本身也可以当做参数去传参 不用函数:组织结构不清晰代码的重复性 def test():#te ...

  2. python2中reload(sys)后设置编码

    python在安装时,默认的编码是ascii,当程序中出现非ascii编码时,python的处理常常会报这样的错UnicodeDecodeError: 'ascii' codec can't deco ...

  3. Leetcode -- 394. Decode String

    Given an encoded string, return it's decoded string. The encoding rule is: k[encoded_string], where ...

  4. from、where、group、with、having、order、union、limit 的使用

    顺序很重要 每次看数据库的一些语法时,都很自然的略过那一大堆的规则,比如说线下面这段select的语法: select [field1,field2...] func_namefrom table1, ...

  5. ocrosoft 程序设计提高期末复习问题M 递归求猴子吃桃

    http://acm.ocrosoft.com/problem.php?cid=1172&pid=12 题目描述 猴子吃桃问题.猴子第1天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个. ...

  6. httpd sshd firewalld 服务后面的d的意思

    在操作系统中,一般系统的服务都是以后台进程的方式存在,而且都会常驻系统中,直到关机才结束.这类服务也称Daemon,在Linux系统中就包含许多的Daemon. 判断Daemon最简单的方法就是从名称 ...

  7. 生成短链接的URL

    假设你想做一个像微博短链接那样的短链接服务,短链接服务生成的URL都非常短例如: http://t.cn/E70Piib, 我们应该都能想到链接中的E70Piib对应的就是存储长链接地址的数据记录的I ...

  8. JS 获取链接中的参数

    1.获取链接全部参数,以对象的形式返回 //获取url中参数 function GetRequest() { var url = location.search; //获取url中"?&qu ...

  9. Oracle RMAN备份与还原注意事项

    1 备份文件管理 如果要删除之前的备份,不要手动去目录下删除,应该在rman命令模式下使用删除命令,否则虽然在磁盘上把物理备份文件删除了,但是使用备份查看命令会一直看到已经删除的备份文件 list b ...

  10. Highgo 瀚高数据库的简单搭建以及处理参数等.

    1. 获取一个瀚高数据库的安装文件 我这边只获取了 瀚高的 2.0.4 的windows x64 版本的. 来源: 同事从供应商那里获取的. 2. windows上面简单安装 很简单 exe 一路ne ...