【Luogu4389】付公主的背包

题目

传送门

解法

答案显然是\(n\)个形如\(\sum_{i \geq 1} x^{vi}\)的多项式的卷积

然而直接NTT的时间复杂度是\(O(nm\log n)\)

我们可以把每个多项式求\(\ln\)然后相加, 在\(\exp\)回去

我们设\(f(x) = \sum_{i \geq 1} x^{vi}\)\(g(x) = \ln(f(x))\)

我们知道\(f(x) = \frac{1}{1-x^v}\)

于是
\[ \begin{align} g'(x) &= \frac{f'(x)}{f(x)}\\ &= \frac{f'(x)}{1/(1-x^v)}\\ &= (1-x^v)f'(x)\\ &= (1-x^v)\sum_{i \geq 1} v\times i\times x^{vi-1}\\ &= \sum_{i \geq 1} v\times i\times x^{vi-1} - \sum_{i \geq 1} v\times i\times x^{vi}\\ &= \sum_{i \geq 1} v\times \left[i - (i-1)\right]\times x^{vi-1}\\ &= \sum_{i \geq 1} v\times x^{vi-1} \end{align} \]

接着积分

\[g(x) = \int g'(x) \mathbb{d}x = \sum_{i \geq 1} \frac{1}{i}x^{vi}\]

最后再跑多项式exp就行了

代码

// luogu-judger-enable-o2
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 400010;

const LL mod = 998244353LL;

inline LL power(LL a, LL n, LL mod)
{   LL Ans = 1;
    while (n)
    {   if (n & 1) Ans = (Ans * a) % mod;
        a = (a * a) % mod;
        n >>= 1;
    }
    return Ans;
}

inline LL Plus(LL a, LL b) { return a + b > mod ? a + b - mod : a + b; }

inline LL Minus(LL a, LL b) { return a - b < 0 ? a - b + mod : a - b; }

struct Mul
{   int Len;

    int rev[N];

    LL wn[N];

    void getReverse()
    {   for (int i = 0; i < Len; i++)
            rev[i] = (rev[i>>1] >> 1) | ((i&1) * (Len >> 1));
    }

    void NTT(LL * a, int opt)
    {   getReverse();
        for (int i = 0; i < Len; i++)
            if (i < rev[i]) swap(a[i], a[rev[i]]);
        int cnt = 0;
        for (int i = 2; i <= Len; i <<= 1)
        {   cnt++;
            for (int j = 0; j < Len; j += i)
            {   LL w = 1;
                for (int k = 0; k < (i>>1); k++)
                {   LL x = a[j + k];
                    LL y = (w * a[j + k + (i>>1)]) % mod;
                    a[j + k] = Plus(x, y);
                    a[j + k + (i>>1)] = Minus(x, y);
                    w = (w * wn[cnt]) % mod;
                }
            }
        }
        if (opt == -1)
        {   reverse(a + 1, a + Len);
            LL num = power(Len, mod-2, mod);
            for (int i = 0; i < Len; i++)
                a[i] = (a[i] * num) % mod;
        }
    }

    void init()
    {   for (int i = 0; i < 23; i++)
            wn[i] = power(3LL, (mod-1) / (1 << i), mod);
    }

    void getLen(int l)
    {   Len = 1;
        for (; Len <= l; Len <<= 1);
    }
} Calc;

void cpy(LL * A, LL * B, int len1, int len2)
{   for (int i = 0; i < len1; i++) A[i] = B[i];
    for (int i = len1; i < len2; i++) A[i] = 0;
}

void getInv(LL * A, LL * B, int len)
{   static LL tmp1[N], tmp2[N];
    B[0] = power(A[0], mod-2, mod);
    for (register int i = 2; i <= len; i <<= 1)
    {   Calc.Len = i << 1;
        cpy(tmp1, A, i, Calc.Len);
        cpy(tmp2, B, i >> 1, Calc.Len);
        Calc.NTT(tmp1, 1);
        Calc.NTT(tmp2, 1);
        for (register int j = 0; j < Calc.Len; j++)
            tmp1[j] = Minus(Plus(tmp2[j], tmp2[j]), tmp2[j] * tmp2[j] % mod * tmp1[j] % mod);
        Calc.NTT(tmp1, -1);
        for (register int j = 0; j < i; j++)
            B[j] = tmp1[j];
    }
}

void getDeri(LL * a, int len)
{   for (int i = 0; i < len; i++)
        a[i] = a[i+1] * (LL) (i+1) % mod;
}

void getInte(LL * a, int len)
{   for (int i = len-1; i >= 1; i--)
        a[i] = a[i-1] * power(i, mod-2, mod) % mod;
    a[0] = 0;
}

void getLn(LL * A, int len)
{   static LL tmp1[N], tmp2[N], tmp3[N];
    Calc.Len = len << 1;
    cpy(tmp1, A, len, Calc.Len);
    cpy(tmp2, A, len, Calc.Len);
    getDeri(tmp1, len);
    getInv(tmp2, tmp3, len);
    Calc.Len = len << 1;
    Calc.NTT(tmp1, 1);
    Calc.NTT(tmp3, 1);
    for (int i = 0; i < Calc.Len; i++)
        tmp1[i] = tmp1[i] * tmp3[i] % mod;
    Calc.NTT(tmp1, -1);
    for (int i = len; i < Calc.Len; i++)
        tmp1[i] = 0;
    getInte(tmp1, len);
    for (int i = 0; i < len; i++)
        A[i] = tmp1[i];
}

void getExp(LL * A, LL * B, int len)
{   static LL tmp1[N], tmp2[N];
    B[0] = 1;
    for (int i = 2; i <= len; i <<= 1)
    {   Calc.Len = i << 1;
        cpy(tmp1, B, i, Calc.Len);
        cpy(tmp2, B, i, Calc.Len);
        getLn(tmp1, i);
        Calc.Len = i << 1;
        for (int j = 0; j < i; j++)
            tmp1[j] = Minus(A[j], tmp1[j]);
        tmp1[0]++;
        Calc.NTT(tmp1, 1);
        Calc.NTT(tmp2, 1);
        for (int j = 0; j < Calc.Len; j++)
            tmp1[j] = (tmp1[j] * tmp2[j]) % mod;
        Calc.NTT(tmp1, -1);
        for (int j = 0; j < Calc.Len; j++)
            B[j] = tmp1[j];
    }
}

LL A[N], B[N], Ans[N];

int cnt[N];

int v[N];

int main()
{   int n, m;
    scanf("%d %d", &n, &m);
    Calc.init();
    for (int i = 1; i <= n; i++)
    {   scanf("%d", &v[i]);
        cnt[v[i]]++;
    }
    Calc.init();
    Calc.getLen(m);
    int len = Calc.Len;
    for (int i = 1; i <= m; i++)
    {   if (!cnt[i]) continue;
        for (int j = i; j <= m; j += i)
            A[j] = Plus(A[j], (LL) cnt[i] * i % mod * power(j, mod-2, mod) % mod);
    }
    getExp(A, Ans, len);
    for (int i = 1; i <= m; i++)
        printf("%lld\n", Ans[i]);
    return 0;
}

转载于:https://www.cnblogs.com/2016gdgzoi509/p/9451562.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业设计,基于SpringBoot+Vue+MySQL开发的精简博客系统,源码+数据库+毕业论文+视频演示 当下,正处于信息化的时代,许多行业顺应时代的变化,结合使用计算机技术向数字化、信息化建设迈进。以前企业对于博客信息的管理和控制,采用人工登记的方式保存相关数据,这种以人力为主的管理模式已然落后。本人结合使用主流的程序开发技术,设计了一款基于Springboot开发的精简博客系统,可以较大地减少人力、财力的损耗,方便相关人员及时更新和保存信息。本系统主要使用B/S开发模式,在idea开发平台上,运用Java语言设计相关的系统功能模块,MySQL数据库管理相关的系统数据信息,SpringBoot框架设计和开发系统功能架构,最后通过使用Tomcat服务器,在浏览器中发布设计的系统,并且完成系统与数据库的交互工作。本文对系统的需求分析、可行性分析、技术支持、功能设计、数据库设计、功能测试等内容做了较为详细的介绍,并且在本文中也展示了系统主要的功能模块设计界面和操作界面,并对其做出了必要的解释说明,方便用户对系统进行操作和使用,以及后期的相关人员对系统进行更新和维护。本系统的实现可以极大地提高企业的工作效率,提升用户的使用体验,因此在现实生活中运用本系统具有很大的使用价值。 关键词:博客管理;Java语言;B/S结构;MySQL数据库
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值