• luogu4389:付公主的背包


    luogu4389:付公主的背包

    题意:

    (nleq 10^5)个东西,每个物品有体积(v_i),有无限件。

    给定(m),对于(sin [1,m]),问用这些物品恰好装(s)体积的方案数。

    (998244353)取模。

    思路:

    如果数据是(10^4),那么这就是一道完全背包的题目。

    但显然此时我们需要效率更高的算法。

    我们知道在求凑成某种数值的方案数的时候可以先设计母函数。

    [G(x)=prod(1+x^{v_i}+x^{2v_i}+...) ]

    这个公式展开后,对于(sin[1,m])的项数的系数就是对应方案数。

    暴力展开的话,时间复杂度会达到(O(n^2logn)),还不如写完全背包。

    考虑优化。

    (i)个物品的多项式为:

    [f(i)=sum_{j=0}x^{jv_i}=frac{1}{1-x^{v_i}} ]

    可能有学过收敛域的同学可能会觉得有些疑惑,(p)级数要求公比的绝对值严格小于(1),这里其实(x)只是一个符号而已,取值自定,所以我可以假设他是小于(1)的公比。

    所以我们需要的多项式就是:

    [g=prod_{i=1}^nf(i) ]

    改乘法为加法:

    [ln(g)=prod ln(f(i))=ln(sum f(i)) ]

    那么多项式如何求(ln)呢?

    [lnf=int frac{f'}{f} ]

    我们把(f(i))带入,下面用(v)代替(v_i)

    [lnf(i)=lnfrac{1}{1-x^v}=int frac{vx^{v-1}}{1-x^v}dx ]

    (f(i)=frac{1}{1-x^v})代入:

    [int vx^{v-1}f(i)=intsum_{i=0}^infin x^{iv} imes vx^{v-1}=intsum_{i=1}^infin vx^{iv-1} ]

    积分:

    [sum_{i=1}^infin frac{1}{i}x^{iv} ]

    这也就是(ln(sum f(i)))了。

    但是我们要求的是(prod f(i)),所以还需要(exp)回来。

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int G = 3;
    const int mod = 998244353;
    const int maxn = 5e5+10;
    
    ll qmi(ll a, ll b)
    {
        ll res = 1;
        while(b)
        {
            if(b&1) res = (res*a)%mod;
            b >>= 1;
            a = (a*a)%mod;
        } return res%mod;
    }
    
    int limit, len, rev[maxn];
    void NTT(ll *c, int op)
    {
        for(int i = 1; i <= limit; i++)
            if(i < rev[i]) swap(c[i], c[rev[i]]);
    
        for(int mid = 1; mid < limit; mid <<= 1)
        {
            ll gn = qmi(G, (mod-1)/(mid<<1));
            if(op == -1) gn = qmi(gn, mod-2);
            for(int j = 0, R = mid<<1; j < limit; j += R)
            {
                ll g = 1;
                for(int k = 0; k < mid; k++, g = (g*gn)%mod)
                {
                    ll x = c[j+k], y = g*c[j+k+mid]%mod;
                    c[j+k] = (x+y)%mod;
                    c[j+k+mid] = (x-y+mod)%mod;
                }
            }
        }
        if(op == 1) return;
        ll inv = qmi(limit, mod-2);
        for(int i = 0; i <= limit; i++) c[i] = c[i]*inv%mod;
    }
    
    ll tmp[maxn];
    void get_inv(ll *a, ll *b, int deg)
    {
    	if(deg == 1)
    	{
    		b[0] = qmi(a[0], mod-2);
    		return;
    	}
    	get_inv(a, b, (deg+1)>>1);
    
    	len = 0, limit = 1;
    	while(limit <= (deg+deg)) limit <<= 1, len++;
    
    	for(int i = 1; i <= limit; i++)
    		rev[i] = (rev[i>>1]>>1)|((i&1)<<(len-1));
    
    	for(int i = 0; i < deg; i++) tmp[i] = a[i];
    	for(int i = deg; i <= limit; i++) tmp[i] = 0;
    
    	NTT(tmp, 1), NTT(b, 1);
    	for(int i = 0; i <= limit; i++)
    		b[i] = 1ll*(2-1ll*tmp[i]*b[i]%mod+mod)%mod*b[i]%mod;
    	NTT(b, -1);
    	for(int i = deg; i <= limit; i++) b[i] = 0;
    }
    
    void deriv(ll *a, int n)
    {
        for(int i = 1; i < n; i++)
            a[i-1] = i*a[i]%mod;
        a[n-1] = 0;
    }
    
    void integ(ll *a, int n)
    {
        for(int i = n-1; i > 0; i--)
            a[i] = a[i-1]*qmi(i, mod-2)%mod;
        a[0] = 0;
    }
    
    void get_ln(ll *a, ll *b, int deg)
    {
        get_inv(a, b, deg);
        for(int i = 0; i < deg; i++)
            tmp[i] = a[i];
        for(int i = deg; i <= limit; i++)
            tmp[i] = 0;
        deriv(tmp, deg);
        NTT(tmp, 1); NTT(b, 1);
        for(int i = 0; i <= limit; i++)
            b[i] = b[i]*tmp[i]%mod;
        NTT(b, -1);
        integ(b, deg);
    }
    
    ll c[maxn];
    void get_exp(ll *a, ll *b, int n)
    {
        if(n == 1) {
            b[0] = 1;
            return;
        }
        get_exp(a, b, (n+1)>>1);
        memset(c, 0, sizeof c);
        get_ln(b, c, n); // c = lnb
        c[0] = (1-c[0]+a[0]+mod)%mod;
        for(int i = 1; i < n; i++)
            c[i] = (a[i]-c[i]+mod)%mod;
        NTT(c, 1); NTT(b, 1);
        for(int i = 0; i <= limit; i++)
            b[i] = b[i]*c[i]%mod;
        NTT(b, -1);
        for(int i = n; i <= limit; i++)
            b[i] = 0;
    }
    
    int n, m;
    int cnt[maxn];
    ll f[maxn], g[maxn];
    
    int main()
    {
        scanf("%d%d", &n, &m);
        for(int i = 1, x; i <= n; i++){
            scanf("%d", &x);
            cnt[x]++;
        }
    
        for(int v = 1; v <= m; v++)
        if(cnt[v])
        {
            for(int iv= v; iv <= m; iv += v)
            f[iv]=(f[iv]+cnt[v]*qmi(iv/v,mod-2)%mod)%mod;
        }
    
        get_exp(f, g, m+1);
        for(int i = 1; i <= m; i++)
            printf("%lld
    ", g[i]);
        return 0;
    }
    
    
  • 相关阅读:
    asp.net core启动源码以及监听,到处理请求响应的过程
    HTTP缓存
    【SpringData&JPA从入门到精通】02JPA API
    关于取地址&和解引用*的小问题
    多态性
    ASP.NET Core WebApi返回结果统一包装实践
    后端思维之数据库性能优化方案
    【项目】项目194
    lambda 表达式
    在APICloud开发平台使用友盟统计功能教程
  • 原文地址:https://www.cnblogs.com/zxytxdy/p/12490277.html
Copyright © 2020-2023  润新知