题目

传送门

解法

答案显然是\(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;
}

【Luogu4389】付公主的背包的更多相关文章

  1. luogu4389 付公主的背包

    题目链接:洛谷 题目大意:现在有$n$个物品,每种物品体积为$v_i$,对任意$s\in [1,m]$,求背包恰好装$s$体积的方案数(完全背包问题). 数据范围:$n,m\leq 10^5$ 这道题 ...

  2. [luogu4389]付公主的背包(多项式exp)

    完全背包方案计数问题的FFT优化.首先写成生成函数的形式:对重量为V的背包,它的生成函数为$\sum\limits_{i=0}^{+\infty}x^{Vi}=\frac{1}{1-x^{V}}$于是 ...

  3. Luogu4389 付公主的背包(生成函数+多项式exp)

    显然构造出生成函数,对体积v的物品,生成函数为1+xv+x2v+……=1/(1-xv).将所有生成函数乘起来得到的多项式即为答案,设为F(x),即F(x)=1/∏(1-xvi).但这个多项式的项数是Σ ...

  4. 洛谷 P4389 付公主的背包 解题报告

    P4389 付公主的背包 题目背景 付公主有一个可爱的背包qwq 题目描述 这个背包最多可以装\(10^5\)大小的东西 付公主有\(n\)种商品,她要准备出摊了 每种商品体积为\(V_i\),都有\ ...

  5. LuoguP4389 付公主的背包【生成函数+多项式exp】

    题目背景 付公主有一个可爱的背包qwq 题目描述 这个背包最多可以装10^5105大小的东西 付公主有n种商品,她要准备出摊了 每种商品体积为Vi,都有10^5105件 给定m,对于s\in [1,m ...

  6. 洛谷P4389 付公主的背包--生成函数+多项式

    题目链接戳这里 题目描述 有\(n\)件不同的商品,每件物品都有无限个,输出总体积为\([1,m]\)的方案数 思路 直接跑背包有\(30\) 考虑把每个物品的生成函数设出来,对于一件体积为\(v\) ...

  7. luogu P4389 付公主的背包

    传送门 神仙题鸭!orz dkw 暴力就是完全背包 而完全背包可以和生成函数扯上关系,记第i种物品质量为\(a_i\),那么这种物品的生成函数\(G(i)=\sum_{j=0}^{\infty}x^{ ...

  8. P3489 付公主的背包

    题意:n<=1e5,m<=1e5,跑n个物品1到m容量的完全背包. 考虑暴力的做法就是把一些1/(1+x^a)的多项式乘起来即可. 考虑优化,取一下ln,转化为加法,然后exp回去就好了.

  9. 洛谷 P4389: 付公主的背包

    题目传送门:洛谷 P4389. 题意简述: 有 \(n\) 个物品,每个物品都有无限多,第 \(i\) 个物品的体积为 \(v_i\)(\(v_i\le m\)). 问用这些物品恰好装满容量为 \(i ...

随机推荐

  1. vue 与 angular 的区别

    vue仅仅是mvvm中的view层,只是一个如jquery般的工具库,而不是框架,而angular而是mvvm框架. vue的双向邦定是基于ES5 中的 getter/setter来实现的,而angu ...

  2. CAD绘制一个半径标注(com接口VB语言)

    主要用到函数说明: _DMxDrawX::DrawDimRadial 绘制一个半径标注.详细说明如下: 参数 说明 DOUBLE dCenterX 被标注的曲线的中点X值 DOUBLE dCenter ...

  3. Python os模块和time模块 day4

    一.os模块 print(os.listdir(r'/Users/smh/Desktop/整理'))#os.listdir() 列出某个目录下面的文件夹/文件 print(os.path.isfile ...

  4. wing ide破解

    LicenseID='CN123-12345-12345-67891' # RequestCode='RL634-8363J-X7E8K-95XD3' RequestCode = 'RW61C-NN6 ...

  5. PHP服务搭建

    一.PHP二进制安装(下载路径http://cn2.php.net/get/php-5.5.32.tar.gz/from/a/mirror) 1.解压: tar xf php-5.5.32.tar.g ...

  6. MySQL之视图、触发器、存储过程、函数、事务、数据库锁

    一.视图 视图:是一个虚拟表,其内容由查询定义.同真实的表一样,视图包含一系列带有名称的列和行数据. 视图的特点: 1.视图的列可以来自不同的表,是表的抽象和逻辑意义上建立的新关系: 2.视图是由基本 ...

  7. 30.IK分词器配置文件讲解以及自定义词库

    主要知识点: 知道IK默认的配置文件信息 自定义词库     一.ik配置文件     ik配置文件地址:es/plugins/ik/config目录     IKAnalyzer.cfg.xml:用 ...

  8. Spring Boot的常见配置项解析

    1.spring-boot-starter-parent:springboot官方推荐的maven管理工具,最简单的做法就是继承它. spring-boot-starter-parent包含了以下信息 ...

  9. node.js 中的package.json文件怎么创建?

    最近在用webstorm和nodejs做一些东西,老是各种混乱,今天上午创建一个新的项目,结果发现,npm init之后,并没有出现package.json,并没有太明确他的功能的小姑娘表示十分的惊慌 ...

  10. mybatis源码阅读-执行器StatementHandle和ParameterHandler(五)

    StatementHandle 类图 各个实现类的作用 SimpleStatementHandler 用于使用Statement操作数据库(不会使用参数化查询?) PreparedStatementH ...