闲话 22.10.19

闲话

听说写一些比较意识流的闲话会像闲话一点(
比方说多头

但是既然都开始写了那就无所谓像了
想啥就写啥吧

话说jjdw打字的手法实在是娴熟
每次看到都想吐槽来着
我还得多练(

话说回来
打KTT的时候一直又WA又T不知道为什么
然后贺了一个加号
然后A了
我不知道为什么

[今天要推的歌是Aster!]
话说下午我在哼安河桥
然后crs吐槽歌十分悲伤
然后我唱Aster 然后问crs为什么不吐槽了
然后crs表示歌很好听

我不是十分的理解

杂题

关于下面的一些讨论,EI 通过了四种方式证明了某个更强的结论

P4389 付公主的背包

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

这个背包最多可以装 \(10^5\) 大小的东西

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

每种商品体积为 \(v_i\),都有无限件

给定 \(m\),对于 \(s\in [1,m]\),请你回答用这些商品恰好装 \(s\) 体积的方案数

\(n,m\le 10^5,v_i \le m\)

板子题。

首先这题用普通完全背包肯定是跑不动的。于是考虑一个多项式优化。

对于一个商品,我们可以把它拆成选 \(k\ (k >= 0)\) 种的可能性加和。
考察单项式相乘的情况:

\[ax^i \times bx^j = abx^{i+j} \]

可以看到,假设我们将可能性看做单项式的系数,背包容量看做单项式的指数,则两个单项式相乘就可以看做背包决策空间内两种决策的合并。推广到多项式,不难得到第 \(k\) 种商品的表示法:

\[f_k(x) = \sum_{i\ge 0} x^{v_k\times i} = \frac 1{1 - x^{v_k}} \]

第二个等号考虑 \(f_k(x) \times x^{v_k} + 1 = f_k(x)\)

于是我们只需要把所有多项式卷积起来,取答案的前 \(m\) 项系数就是答案。
但是如果直接卷复杂度就是 \(O(n^2 \log n)\) 的了。然后考虑优化。

\(G(x)\) 为答案的生成函数。立得

\[G(x) = \prod_{i=1}^n f_i(x) = \frac 1 {\prod_{i=1}^n (1 - x^{v_i})} \]

我们只需要求出分母,求个逆就是答案。
然后考虑分母:

\[\begin{aligned} \prod_{i=1}^n (1 - x^{v_i}) & = \exp \ln(\sum_{i=1}^n (1 - x^{v_i})) \\ & = \exp \sum_{i=1}^n \ln(1 - x^{v_i}) \\ & = \exp \sum_{i=1}^n -\sum_{j\ge 1} \frac{x^{v_ij}}{j} \\ & = \exp \sum_{j\ge 1} -\frac 1{j} \sum_{i=1}^n x^{v_i j} \\ & = \exp \sum_{j\ge 1} -\frac 1{j} \sum_{jk \le m} x^{jk} \sum_{i=1}^n [v_i = k] \end{aligned}\]

第三步考虑一个 \(\ln(1-x^k)\) 的麦克劳林展开。
随后我们就可以通过用一个桶预处理第三个求和号,用 \(O(\sum_{i=1}^m \frac mi) = O(m \log m)\) 的时间得到需要的前 \((m+1)\) 项。

得到所有系数后做一次 \(\exp\) 做一次求逆即可得到答案。

code
#include <bits/stdc++.h>
#include <bits/extc++.h>
#define rep(i, a, b) for (register int(i) = (a), i##_ = (b) + 1; (i) < i##_; ++(i))
#define pre(i, a, b) for (register int(i) = (a), i##_ = (b) - 1; (i) > i##_; --(i))
using namespace std;

const int N = 3e5 + 10, mod = 998244353, g = 3;
const int siz_int = sizeof(int);

#ifdef ONLINE_JUDGE
    char buf[1<<21], *p1 = buf, *p2 = buf;  inline char getc() { return (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1<<21, stdin), p1 == p2) ? EOF : *p1++); }
    #define getchar getc
#endif
template <typename T> inline void get(T & x){
	x = 0; char ch = getchar(); bool f = false; while (ch < '0' or ch > '9') f = f or ch == '-',  ch = getchar();
	while (ch >= '0' and ch <= '9') x = (x<<1) + (x<<3) + (ch^48), ch = getchar(); f && (x = -x);
} template <typename T, typename ... Args> inline void get(T & x, Args & ... _Args) { get(x); get(_Args...); }

int n, m, len = 1, a[N], cnt[N], ifv[N];

typedef long long ll; typedef __int128 lll;
struct FastMod { int m; ll b; FastMod(int _m) { m = _m; b = ((lll)1<<64) / m; } int operator() (ll a) {ll q = ((lll)a * b) >> 64; a -= q * m; if (a >= m) a -= m; return a; } } Mod(mod);
int add(int a, int b) { return (a += b) >= mod ? a - mod : a; } template <typename ...Args> int add(int a, Args ...b) { return add(a, add(b...)); }
int mul(int a, int b) { return Mod(1ll * a * b); } template <typename ...Args> int mul(int a, Args ...b) { return mul(a, mul(b...)); }

int btrs[N << 1];
inline int initrs(int k) {
    int limit = 1;
    while (limit < k) limit <<= 1;
    for (register int i = 0 ; i < limit; i ++) btrs[i] = (btrs[i >> 1] >> 1) | ((i & 1) ? limit >> 1 : 0);
    return limit;
}

inline int qp(int a, int b) {
    int ret = 1;
    while (b) {
        if (b & 1) ret = mul(ret, a);
        a = mul(a, a);
        b >>= 1;
    } return ret;
} inline int inv(int a) { return qp(a, mod-2); }
const int invg = inv(g), inv2 = (mod + 1) >> 1;

const int L = 1 << 21;
int w[2][L];
int IUR() {
    w[0][0] = w[1][0] = 1; int wn = qp(g, (mod-1) / L);
    for (register int i = 1; i < L; i++) w[0][L - i] = w[1][i] = mul(w[1][i - 1], wn);
    return 1;
} int dummy = IUR();

struct poly {
    vector <int> f; 
    int operator [] (const int & pos) const { return f[pos]; }
    int & operator [] (const int & pos) { return f[pos]; }
    int deg() {return f.size(); }
    int deg() const  {return f.size(); }
    void Set(int n) { f.resize(n); }
    void Adjust() { while (f.size() > 1 and f.back() == 0) f.pop_back(); }
    void Reverse() { reverse(f.begin(), f.end()); }
    void scan(int n = -1) { if (n < 0) get(n); Set(n); for (register int i = 0; i < n; i++) get(f[i]); }
    void print() { for (int x : f) printf("%d ", x); }
	void getFac(int k) { Set(k); f[0] = 1; for (int i = 1; i <= k; i++) f[i] = mul(f[i - 1], i); }
	void getInv(int k) { Set(k); f[0] = f[1] = 1; for (int i = 1; i <= k; ++ i) f[i] = mul(mod - mod / i, f[mod % i]); }
    void deri() { for (register int i = 0; i + 1 < (int)f.size(); ++i) f[i] = mul(f[i+1], i+1); f.back() = 0; }
    void intg() { for (register int i = f.size() - 1; i >= 1; --i) f[i] = mul(f[i-1], inv(i)); f[0] = 0; }
    poly Deri() { 
        poly ret; ret.Set(deg());
        for (int i = 0; i + 1 < deg(); ++i) {
            ret[i] = mul(f[i+1], i+1);
        } return ret;
    } poly Intg() {
        poly ret, inv; ret.Set(deg()), inv.getInv(deg() - 1);
        for (int i = deg() - 1; i >= 1; --i) {
            ret[i] = mul(f[i-1], inv[i]);
        } return ret;
    }
    inline void NTT (const int lim, const int type) {
        Set(lim); 
        for (register int i = 0; i < lim; i++) if (i < btrs[i]) swap(f[i], f[btrs[i]]);
        for (register int mid = 1, x, y; mid < lim; mid <<= 1) {
            for (register int i = L / (mid<<1), j = 0; j < lim; j += (mid << 1)) {
                for (register int k = 0; k < mid; k++) {
                    x = f[j + k], y = mul(w[type][i * k], f[j + k + mid]);
                    f[j + k] = add(x, y);
                    f[j + k + mid] = add(x, mod - y);
                }
            }
        } if (type == 1) return;
        int inv = qp(lim, mod - 2);
        for (register int i = 0; i < lim; i++) f[i] = mul(f[i], inv);
    } 
    friend poly operator + (const poly & x, const poly & y) {
        poly ret; ret.Set(max(x.deg(), y.deg()));
        for (register int i = 0; i < x.deg(); ++i) ret[i] = x[i];
        for (register int i = 0; i < y.deg(); ++i) ret[i] = add(ret[i], y[i]);
        return ret;
    } void operator += (const poly & x) {
        Set(max(deg(), x.deg()));
        for (register int i = 0; i < x.deg(); ++i) f[i] = add(f[i], x[i]);
    } 
    friend poly operator - (const poly & x, const poly & y) {
        poly ret; ret.Set(max(x.deg(), y.deg()));
        for (register int i = 0; i < x.deg(); ++i) ret[i] = x[i];
        for (register int i = 0; i < y.deg(); ++i) ret[i] = add(ret[i], mod - y[i]);
        return ret;
    } void operator -= (const poly & x) {
        Set(max(deg(), x.deg()));
        for (register int i = 0; i < x.deg(); ++i) f[i] = add(f[i], mod - x[i]);
    } 
    friend poly operator * (const poly & x, const poly & y) {
        poly ret, A = x, B = y;
        int limit = initrs(A.deg() + B.deg() - 1);
        A.NTT(limit, 1), B.NTT(limit, 1); ret.Set(limit);
        for (register int i = 0; i < limit; i++) ret[i] = mul(A[i], B[i]);
        ret.NTT(limit, 0); ret.Adjust();
        return ret;
    } void operator *= (const poly & x) {
        poly A = x;
        int limit = initrs(deg() + A.deg() - 1);
        A.NTT(limit, 1); NTT(limit, 1);
        for (register int i = 0; i < limit; i++) f[i] = mul(A[i], f[i]);
        NTT(limit, 0); Adjust();
    }
    poly Inv() {
        poly ret; ret.Set(1);
        if (f.empty()) return ret;
        ret[0] = inv(f[0]); poly A, B;
        for (register int len = 2, limit; len < (deg() << 1); len <<= 1) {
            A.f.assign((*this).f.begin(), (*this).f.begin() + min(len, deg()));
            B = ret; B.Set(min(len, deg()));
            limit = initrs(A.deg() + B.deg() - 1);
            A.NTT(limit, 1); B.NTT(limit, 1);
            ret.Set(limit);
            for (register int i = 0; i < limit; i++) ret[i] = mul(add(2, mod - mul(A[i], B[i])), B[i]);
            ret.NTT(limit, 0);
            ret.Set(len);
        } ret.Set(deg()); return ret;
    }
    poly Ln() {
        poly ret = Deri(), Iv = Inv();
        ret *= Iv; ret.intg(); ret.Set(deg());
        return ret;
    } 
    poly Exp() {
        poly ret; ret.Set(1); ret[0] = 1;
        poly A, B;
        for (register int len = 2; len < (deg() << 1); len <<= 1) {
            ret.Set(len); A = ret.Ln();
            B.f.assign((*this).f.begin(), (*this).f.begin() + min(len, deg()));
            B -= A; B[0]++; ret *= B;
            ret.Set(len);
        } ret.Set(deg()); return ret;
    }
} F;

signed main() {
    get(n, m);
    rep(i,1,n) get(a[i]), cnt[a[i]]++;
    while (len <= m) len <<= 1;
    ifv[0] = ifv[1] = 1;
    rep(i,2,len) ifv[i] = mul((mod - mod / i), ifv[mod % i]);
    F.Set(len); 
    rep(i,1,m) if (cnt[i]) {
        for (int j = 1; i * j < len; ++ j) {
            F[i * j] = add(F[i * j], mul(cnt[i], (mod - ifv[j])));
        }
    }
    F = F.Exp();
    F = F.Inv();
    rep(i,1,m) printf("%d\n", F[i]);
}



actually还做了一道题 P5175
但是太水了略去

但是想请各位卡卡常(



[能不能再给力一点啊?]

P7435 简单的排列计数

题面比较形式化,在此不放。

多项式题。

由经典dp结论,我们有 答案即为

\[[x^k]\prod_{i=1}^n \frac{1-(ix)^i}{1 - ix} \]

\[\prod_{i=1}^n \frac{1-(ix)^i}{1 - ix} = \exp\left( \sum_{i=1}^n \ln(1-(ix)^i) - \ln(1-ix) \right) \]

讨论减号前后的两个部分。

首先是前面的:

\[\begin{aligned} \sum_{i=1}^n \ln(1-(ix)^i) & = - \sum_{i=1}^n\sum_{j\ge1} \frac {(ix)^{ij}}{j} \\ & = \sum_{j\ge 1} -\frac 1{j} \sum_{ij \le n} i^{ij} \times x^{i j} \end{aligned}\]

\(n,k\) 其实是同阶的。直接算就完了。

然后是后面的:

\[\begin{aligned} \sum_{i=1}^n \ln(1-ix) & = - \sum_{i=1}^n\sum_{j\ge1} \frac {(ix)^{j}}{j} \\ & = \sum_{j\ge1} \frac {x^{j}}{j} \sum_{i=1}^n i^j \\ & = \sum_{j\ge1} \frac {x^{j}}{j} \left( \frac 1{j+1}\sum_{i-1}^j \binom{j+1}{i}B_i(n+1)^{j-i+1} \right)j \\ & = \sum_{j\ge1} \frac {x^{j}}{j(j+1)} \sum_{i-1}^j \binom{j+1}{i}B_i(n+1)^{j-i+1} \end{aligned}\]

\(B_i\) 是伯努利数。对多项式大佬来说显然不是什么问题
\(B_i\) 的EGF是 \(\frac x {e^x - 1}\)

于是我们就能得到答案了。

懒得写码了(

posted @ 2022-10-19 19:44  joke3579  阅读(53)  评论(0编辑  收藏  举报