LuoguP4389 付公主的揹包【生成函式+多項式exp】
阿新 • • 發佈:2019-01-02
題目背景
付公主有一個可愛的揹包qwq
題目描述
這個揹包最多可以裝10^5105大小的東西
付公主有n種商品,她要準備出攤了
每種商品體積為Vi,都有10^5105件
給定m,對於s\in [1,m]s∈[1,m],請你回答用這些商品恰好裝s體積的方案數
輸入輸出格式
輸入格式:
第一行n,m
第二行V1~Vn
輸出格式:
m行,第i行代表s=i時方案數,對998244353取模
輸入輸出樣例
輸入樣例#1:
2 4
1 2
輸出樣例#1:
1
2
2
3
說明
對於30%的資料,n<=3000,m<=3000
對於60%的資料,純隨機生成
對於100%的資料, n<=100000,m<=100000
對於100%的資料,Vi<=m
思路
首先我們得到這道題是n個形如\(\sum_{i=0}^{\infin}x^{vi}\)的生成函式的乘積,然後考慮優化
因為這裡個數的上限是\(1e5\)可以看做無限大
所以我們可以得到
\[ f(x)=\sum_{i=0}x^{vi}=\frac{1}{1-x^{v}} \]
然後因為直接多項式相乘非常麻煩
考慮取ln之後相加
\[ g(x)=ln(f(x)) \]
求一波導數
\[ g'(x)=\frac{f'(x)}{f(x)}=(1-x^v)\sum_{i=1}vi*x^{vi-1} \]
然後把\((1-x^v)\)展開變成
\[ g'(x)=\sum_{i=1}v*x^{vi-1} \]
所以
\[ g(x)=\sum_{i=1}\frac{1}{i}x^{vi} \]
這樣的話多項式的有效項數和是一個調和級數
所以多項式加\(\O(n\log n)\)
然後exp回去
#include<bits/stdc++.h> using namespace std; int read() { int res = 0; char c = getchar(); while (!isdigit(c)) c = getchar(); while (isdigit(c)) res = (res << 1) + (res << 3) + c - '0', c = getchar(); return res; } typedef long long ll; typedef vector<int> Poly; const int N = 3e5 + 10; const int Mod = 998244353; const int G = 3; int add(int a, int b, int mod = Mod) { return (a += b) >= mod ? a - mod : a; } int sub(int a, int b, int mod = Mod) { return (a -= b) < 0 ? a + mod : a; } int mul(int a, int b, int mod = Mod) { return 1ll * a * b % mod; } int fast_pow(int a, int b, int mod = Mod) { int res = 1; for (; b; b >>= 1, a = mul(a, a, mod)) if (b & 1) res = mul(res, a, mod); return res; } int w[2][N]; void init() { int wn; for (int i = 1; i < (1 << 18); i <<= 1) { w[1][i] = w[0][i] = 1; wn = fast_pow(G, (Mod - 1) / (i << 1)); for (int j = 1; j < i; j++) w[1][i + j] = mul(wn, w[1][i + j - 1]); wn = fast_pow(G, Mod - 1 - (Mod - 1) / (i << 1)); for (int j = 1; j < i; j++) w[0][i + j] = mul(wn, w[0][i + j - 1]); } } void transform(int *t, int len, int typ) { for (int i = 0, j = 0, k; j < len; j++) { if (j > i) swap(t[i], t[j]); for (k = (len >> 1); k & i; k >>= 1) i ^= k; i ^= k; } for (int i = 1; i < len; i <<= 1) { for (int j = 0; j < len; j += (i << 1)) { for (int k = 0; k < i; k++) { int x = t[j + k], y = mul(w[typ][i + k], t[i + j + k]); t[j + k] = add(x, y); t[j + k + i] = sub(x, y); } } } if (typ) return; int inv = fast_pow(len, Mod - 2); for (int i = 0; i < len; i++) t[i] = mul(t[i], inv); } void print(Poly a) { for (size_t i = 0; i < a.size(); i++) { cout<<a[i]<<" "; }cout<<endl; } void clean(Poly &a) { while (a.size() && !a.back()) a.pop_back(); } Poly add(Poly a, Poly b) { a.resize(max(a.size(), b.size())); for (size_t i = 0; i < b.size(); i++) a[i] = add(a[i], b[i]); return a; } Poly sub(Poly a, Poly b) { a.resize(max(a.size(), b.size())); for (size_t i = 0; i < b.size(); i++) a[i] = sub(a[i], b[i]); return a; } Poly mul(const Poly &a, const Poly &b) { int len = a.size() + b.size() + 1; len = 1 << (int) ceil(log2(len)); static Poly prea, preb; prea = a; preb = b; prea.resize(len); preb.resize(len); transform(&prea[0], len, 1); transform(&preb[0], len, 1); for (int i = 0; i < len; i++) prea[i] = mul(prea[i], preb[i]); transform(&prea[0], len, 0); clean(prea); return prea; } Poly inv(Poly a, int n) { if (n == 1) return Poly(1, fast_pow(a[0], Mod - 2)); int len = 1 << ((int) ceil(log2(n)) + 1); Poly x = inv(a, (n + 1) >> 1), y; x.resize(len); y.resize(len); for (int i = 0; i < n; i++) y[i] = a[i]; transform(&x[0], len, 1); transform(&y[0], len, 1); for (int i = 0; i < len; i++) x[i] = mul(x[i], sub(2, mul(x[i], y[i]))); transform(&x[0], len, 0); x.resize(n); return x; } Poly inv(Poly a) { return inv(a, a.size()); } Poly deri(Poly a) { int n = a.size(); for (int i = 1; i < n; i++) a[i - 1] = mul(a[i], i); a.resize(n - 1); return a; } Poly inte(Poly a) { int n = a.size(); a.resize(n + 1); for (int i = n; i >= 1; i--) a[i] = mul(a[i - 1], fast_pow(i, Mod - 2)); a[0] = 0; return a; } Poly ln(Poly a) { int len = a.size(); a = inte(mul(deri(a), inv(a))); a.resize(len); return a; } Poly exp(Poly a, int n) { if (n == 1) return Poly(1, 1); Poly x = exp(a, (n + 1) >> 1), y; x.resize(n); y = ln(x); for (int i = 0; i < n; i++) y[i] = sub(a[i], y[i]); y[0]++; x = mul(x, y); x.resize(n); return x; } Poly exp(Poly a) { return exp(a, a.size()); } int n, m, cnt[N], invf[N]; int main() { init(); n = read(), m = read(); for (int i = 1; i <= n; i++) cnt[read()]++; Poly a(m + 1); for (int i = 1; i <= m; i++) invf[i] = fast_pow(i, Mod - 2); for (int i = 1; i <= m; i++) if (cnt[i]) { for (int j = i; j <= m; j += i) { a[j] = add(a[j], mul(invf[j / i], cnt[i])); } } clean(a); a = exp(a); a.resize(m + 1); for (int i = 1; i <= m; i++) printf("%d\n", a[i]); return 0; }