1. 程式人生 > >LuoguP4389 付公主的揹包【生成函式+多項式exp】

LuoguP4389 付公主的揹包【生成函式+多項式exp】

題目背景

付公主有一個可愛的揹包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;
}