zoukankan      html  css  js  c++  java
  • LuoguP4389 付公主的背包【生成函数+多项式exp】

    题目背景

    付公主有一个可爱的背包qwq

    题目描述

    这个背包最多可以装10^5105大小的东西

    付公主有n种商品,她要准备出摊了

    每种商品体积为Vi,都有10^5105件

    给定m,对于sin [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(nlog 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
    ", a[i]); 
      return 0;
    } 
    
  • 相关阅读:
    Eclipse背景颜色修改
    使用主键或者索引提高SQL语句效率的建议
    Mysql批量插入executeBatch测试
    【php增删改查实例】第十三节
    【php增删改查实例】第十二节
    【php增删改查实例】第十一节
    【php增删改查实例】第十节
    【php增删改查实例】第九节
    【php增删改查实例】第八节
    【php增删改查实例】第六节
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/10210577.html
Copyright © 2011-2022 走看看