传送门:https://www.luogu.com.cn/problem/P4389
题意
有 n 个 物 品 , 每 个 物 品 体 积 为 v i , 给 定 一 个 m , 问 这 些 物 品 恰 好 装 [ 1 , m ] 的 方 案 数 。 有n个物品,每个物品体积为v_i,给定一个m,问这些物品恰好装[1,m]的方案数。 有n个物品,每个物品体积为vi,给定一个m,问这些物品恰好装[1,m]的方案数。
思路
如
果
数
据
量
小
,
则
可
以
背
包
。
如果数据量小,则可以背包。
如果数据量小,则可以背包。
但
问
题
是
,
n
和
m
都
有
1
e
5
,
不
可
能
背
包
的
。
但问题是,n和m都有1e5,不可能背包的。
但问题是,n和m都有1e5,不可能背包的。
因 为 是 一 类 计 数 问 题 , 所 以 考 虑 生 成 函 数 。 因为是一类计数问题,所以考虑生成函数。 因为是一类计数问题,所以考虑生成函数。
设 只 装 一 个 物 品 体 积 v , 它 可 以 用 多 大 的 背 包 , 那 就 是 v , 2 v , . . n v 。 设只装一个物品体积v,它可以用多大的背包,那就是v,2v,..nv。 设只装一个物品体积v,它可以用多大的背包,那就是v,2v,..nv。
设 生 成 函 数 为 F ( x ) = ∑ i = 0 ∞ x i v 设生成函数为F(x)=\sum_{i=0}^{\infty }x^{iv} 设生成函数为F(x)=∑i=0∞xiv
则
,
对
于
一
个
s
背
包
,
a
n
s
=
所
有
生
成
函
数
卷
积
,
则
复
杂
度
为
O
(
n
log
n
)
。
则,对于一个s背包,ans=所有生成函数卷积,则复杂度为O(n\log n)。
则,对于一个s背包,ans=所有生成函数卷积,则复杂度为O(nlogn)。
对
于
[
1
,
m
]
所
有
背
包
,
复
杂
度
为
O
(
m
n
log
n
)
,
也
很
爆
炸
对于[1,m]所有背包,复杂度为O(mn\log n),也很爆炸
对于[1,m]所有背包,复杂度为O(mnlogn),也很爆炸
所 以 考 虑 生 成 函 数 的 封 闭 形 式 来 简 化 问 题 。 所以考虑生成函数的封闭形式来简化问题。 所以考虑生成函数的封闭形式来简化问题。
F ( x ) = ∑ i = 0 ∞ x i v = 1 1 − x v F(x)=\sum_{i=0}^{\infty }x^{iv}=\frac{1}{1-x^{v}} F(x)=∑i=0∞xiv=1−xv1
那
我
们
可
以
把
封
闭
形
式
的
求
卷
积
,
再
来
一
个
多
项
式
求
逆
。
那我们可以把封闭形式的求卷积,再来一个多项式求逆。
那我们可以把封闭形式的求卷积,再来一个多项式求逆。
复
杂
度
为
O
(
2
m
)
,
还
是
爆
炸
,
那
怎
么
办
呢
?
复杂度为O(2^m),还是爆炸,那怎么办呢?
复杂度为O(2m),还是爆炸,那怎么办呢?
上 面 两 种 方 法 , 都 是 因 为 卷 积 , 如 果 我 们 能 不 乘 法 , 而 改 为 加 法 , 那 复 杂 度 是 不 是 可 以 了 ? 上面两种方法,都是因为卷积,如果我们能不乘法,而改为加法,那复杂度是不是可以了? 上面两种方法,都是因为卷积,如果我们能不乘法,而改为加法,那复杂度是不是可以了?
乘 法 变 加 法 , 取 对 数 , 多 项 式 取 ln 的 复 杂 度 也 是 O ( n log n ) , 那 对 所 有 的 F ( x ) 取 , 不 是 也 会 T 吗 ? 乘法变加法,取对数,多项式取\ln的复杂度也是O(n\log n),那对所有的F(x)取,不是也会T吗? 乘法变加法,取对数,多项式取ln的复杂度也是O(nlogn),那对所有的F(x)取,不是也会T吗?
先 来 看 看 这 个 多 项 式 取 ln 是 什 么 形 式 。 先来看看这个多项式取\ln 是什么形式。 先来看看这个多项式取ln是什么形式。
设 G ( x ) = ln F ( x ) , 则 设G(x)=\ln F(x),则 设G(x)=lnF(x),则
G ′ ( x ) = F ′ ( x ) F ( x ) G'(x)=\frac{F'(x)}{F(x)} G′(x)=F(x)F′(x)
G ′ ( x ) = − − v ∗ x v − 1 1 − x v G'(x)=-\frac{-v*x^{v-1}}{1-x^{v}} G′(x)=−1−xv−v∗xv−1
G ′ ( x ) = v ∗ x v − 1 1 − x v G'(x)=\frac{v*x^{v-1}}{1-x^v} G′(x)=1−xvv∗xv−1
G ′ ( x ) = v x v − 1 ∗ ∑ i = 0 ∞ x i v G'(x)=vx^{v-1}*\sum_{i=0}^{\infty} x^{iv} G′(x)=vxv−1∗i=0∑∞xiv
G ′ ( x ) = v ∑ i = 0 ∞ x i v + v − 1 G'(x)=v\sum_{i=0}^{\infty} x^{iv+v-1} G′(x)=vi=0∑∞xiv+v−1
G ( x ) = v ∑ i = 0 ∞ x i v + v i v + v G(x)=v\sum_{i=0}^{\infty} \frac{x^{iv+v}}{iv+v} G(x)=vi=0∑∞iv+vxiv+v
G ( x ) = ∑ i = 0 ∞ x v ( i + 1 ) i + 1 G(x)=\sum_{i=0}^{\infty}\frac{x^{v(i+1)}}{i+1} G(x)=i=0∑∞i+1xv(i+1)
G ( x ) = ∑ i = 1 ∞ x i v i G(x)=\sum_{i=1}^{\infty}\frac{x^{iv}}{i} G(x)=i=1∑∞ixiv
所 以 我 们 可 以 先 对 每 个 物 品 的 体 积 计 数 , 然 后 分 配 给 对 应 的 x i 。 所以我们可以先对每个物品的体积计数,然后分配给对应的x^i。 所以我们可以先对每个物品的体积计数,然后分配给对应的xi。
最 后 多 项 式 e x p 得 到 原 来 多 项 式 , 并 输 出 。 最后多项式exp得到原来多项式,并输出。 最后多项式exp得到原来多项式,并输出。
Code
#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<double, double> pdd;
typedef pair<ll, ll> pll;
#define endl "\n"
#define eb emplace_back
#define mem(a, b) memset(a , b , sizeof(a))
const ll INF = 0x3f3f3f3f;
const ll mod = 998244353;
// const ll mod = 1e9 + 7;
const double eps = 1e-6;
const double PI = acos(-1);
const double R = 0.57721566490153286060651209;
const int N = 4e5 + 10;
struct Complex {
double x, y;
Complex(double a = 0, double b = 0): x(a), y(b) {}
Complex operator + (const Complex &rhs) { return Complex(x + rhs.x, y + rhs.y); }
Complex operator - (const Complex &rhs) { return Complex(x - rhs.x, y - rhs.y); }
Complex operator * (const Complex &rhs) { return Complex(x * rhs.x - y * rhs.y, x * rhs.y + y * rhs.x); }
Complex conj() { return Complex(x, -y); }
} w[N];
int tr[N];
ll EXP[N], V[N], ans[N];
ll quick_pow(ll a, ll b) {
ll ans = 1;
while(b) {
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans % mod;
}
int getLen(int n) {
int len = 1; while (len < (n << 1)) len <<= 1;
for (int i = 0; i < len; i++) tr[i] = (tr[i >> 1] >> 1) | (i & 1 ? len >> 1 : 0);
for (int i = 0; i < len; i++) w[i] = w[i] = Complex(cos(2 * PI * i / len), sin(2 * PI * i / len));
return len;
}
void FFT(Complex *A, int len) {
for (int i = 0; i < len; i++) if(i < tr[i]) swap(A[i], A[tr[i]]);
for (int i = 2, lyc = len >> 1; i <= len; i <<= 1, lyc >>= 1)
for (int j = 0; j < len; j += i) {
Complex *l = A + j, *r = A + j + (i >> 1), *p = w;
for (int k = 0; k < i >> 1; k++) {
Complex tmp = *r * *p;
*r = *l - tmp, *l = *l + tmp;
++l, ++r, p += lyc;
}
}
}
inline void MTT(ll *x, ll *y, ll *z, int len) {
for (int i = 0; i < len; i++) (x[i] += mod) %= mod, (y[i] += mod) %= mod;
static Complex a[N], b[N];
static Complex dfta[N], dftb[N], dftc[N], dftd[N];
for (int i = 0; i < len; i++) a[i] = Complex(x[i] & 32767, x[i] >> 15);
for (int i = 0; i < len; i++) b[i] = Complex(y[i] & 32767, y[i] >> 15);
FFT(a, len), FFT(b, len);
for (int i = 0; i < len; i++) {
int j = (len - i) & (len - 1);
static Complex da, db, dc, dd;
da = (a[i] + a[j].conj()) * Complex(0.5, 0);
db = (a[i] - a[j].conj()) * Complex(0, -0.5);
dc = (b[i] + b[j].conj()) * Complex(0.5, 0);
dd = (b[i] - b[j].conj()) * Complex(0, -0.5);
dfta[j] = da * dc;
dftb[j] = da * dd;
dftc[j] = db * dc;
dftd[j] = db * dd;
}
for (int i = 0; i < len; i++) a[i] = dfta[i] + dftb[i] * Complex(0, 1);
for (int i = 0; i < len; i++) b[i] = dftc[i] + dftd[i] * Complex(0, 1);
FFT(a, len), FFT(b, len);
for (int i = 0; i < len; i++) {
ll da = (ll)(a[i].x / len + 0.5) % mod;
ll db = (ll)(a[i].y / len + 0.5) % mod;
ll dc = (ll)(b[i].x / len + 0.5) % mod;
ll dd = (ll)(b[i].y / len + 0.5) % mod;
z[i] = (da + ((ll)(db + dc) << 15) + ((ll)dd << 30)) % mod;
}
}
void Get_Inv(ll *f, ll *g, int n) {
if(n == 1) { g[0] = quick_pow(f[0], mod - 2); return ; }
Get_Inv(f, g, (n + 1) >> 1);
int len = getLen(n);
static ll c[N];
for(int i = 0;i < len; i++) c[i] = i < n ? f[i] : 0;
MTT(c, g, c, len); MTT(c, g, c, len);
for(int i = 0;i < n; i++) g[i] = (2ll * g[i] - c[i] + mod) % mod;
for(int i = n;i < len; i++) g[i] = 0;
for(int i = 0;i < len; i++) c[i] = 0;
}
void Get_Der(ll *f, ll *g, int len) { for(int i = 1;i < len; i++) g[i - 1] = f[i] * i % mod; g[len - 1] = 0; }
void Get_Int(ll *f, ll *g, int len) { for(int i = 1;i < len; i++) g[i] = f[i - 1] * quick_pow(i, mod - 2) % mod; g[0] = 0; }
void Get_Ln(ll *f, ll *g, int n) {
static ll a[N], b[N];
Get_Der(f, a, n);
Get_Inv(f, b, n);
int len = getLen(n);
MTT(a, b, a, len);
Get_Int(a, g, len);
for(int i = n;i < len; i++) g[i] = 0;
for(int i = 0;i < len; i++) a[i] = b[i] = 0;
}
void Get_Exp(ll *f, ll *g, int n) {
if(n == 1) return (void)(g[0] = 1);
Get_Exp(f, g, (n + 1) >> 1);
static ll a[N];
Get_Ln(g, a, n);
a[0] = (f[0] + 1 - a[0] + mod) % mod;
for(int i = 1;i < n; i++) a[i] = (f[i] - a[i] + mod) % mod;
int len = getLen(n);
MTT(a, g, g, len);
for(int i = n;i < len; i++) g[i] = 0;
for(int i = 0;i < len; i++) a[i] = 0;
}
void solve() {
int n, m; cin >> n >> m;
for(int i = 1;i <= n; i++) {
int v; cin >> v;
V[v]++;
}
for(int v = 1;v <= m; v++) {
if(V[v]) {
for(int i = 1;i <= m / v; i++) {
EXP[i * v] = (EXP[i * v] + 1ll * V[v] * quick_pow(i, mod - 2)) % mod;
}
}
}
Get_Exp(EXP, ans, m + 1);
for(int i = 1;i <= m; i++) cout << ans[i] << endl;
}
signed main() {
ios_base::sync_with_stdio(false);
// cin.tie(nullptr);
// cout.tie(nullptr);
#ifdef FZT_ACM_LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
signed test_index_for_debug = 1;
char acm_local_for_debug = 0;
do {
if (acm_local_for_debug == '$') exit(0);
if (test_index_for_debug > 20)
throw runtime_error("Check the stdin!!!");
auto start_clock_for_debug = clock();
solve();
auto end_clock_for_debug = clock();
cout << "Test " << test_index_for_debug << " successful" << endl;
cerr << "Test " << test_index_for_debug++ << " Run Time: "
<< double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
cout << "--------------------------------------------------" << endl;
} while (cin >> acm_local_for_debug && cin.putback(acm_local_for_debug));
#else
solve();
#endif
return 0;
}