zoukankan      html  css  js  c++  java
  • 【XSY2759】coin DP 线性插值

    题目描述

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

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

      (nleq 50,mleq {10}^{18})

    题解

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

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

      那么考虑从小到大取钱。

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

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

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

    [egin{align} f_i(x)&=sum_{j=0}^x f_{i-1}(frac{ja_i+mmod 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
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    可图性判定HavelHakimi定理
    并查集入门
    js数组和函数应用
    DOM用法及应用
    javascript基础知识
    表单
    PHP变量
    30天自制操作系统开发笔记——IDT中断描述符表
    《30天自制操作系统》学习笔记——汇编程序磁盘BIOS调用
    汇编指令: LGDT、LIDT、LLDT、LMSW、LOADALL、LOADALL286、LOCK、LODSB、LODSW、LODSD
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8681022.html
Copyright © 2011-2022 走看看