CF923E Perpetual Subtraction

发布时间 2023-07-24 22:21:37作者: Ender_32k

参考了 cmd 的多项式计数杂谈,拜谢。

考虑题目给定的其实就是 \(x\) 分布的 PGF \(F(x)\)。那么令 \(F_i(x)\) 表示操作了 \(i\) 轮后 \(x\) 的 PGF,则 \(F_0(x)=F(x)\)

考虑一次操作对 \(x\) 的影响,若操作成了 \(k\)

\[[x^k]F_{i}(x)=\sum\limits_{j=k}[x^j]\frac{F_{i-1}(x)}{j+1} \]

于是:

\[\begin{aligned}F_i(x)&=\sum\limits_{k}x^k\sum\limits_{j=k}[x^j]\frac{F_{i-1}(x)}{j+1}\\&=\sum\limits_{j}[x^j]\frac{F_{i-1}(x)}{j+1}\sum\limits_{k=0}^jx^k\\&=\sum\limits_{j}[x^j]\frac{F_{i-1}(x)}{j+1}\cdot\frac{x^{j+1}-1}{x-1}\\&=\frac{1}{x-1}\sum\limits_{j}\frac{x^{j+1}-1}{j+1}[x^j]F_{i-1}(x)\end{aligned} \]

这个分式好像有点眼熟,回忆幼数课本:

\[\int x^jdx=\frac{x^{j+1}}{j+1} \]

那么把 \(1\) 当成 \(1^{j+1}\)

\[\begin{aligned}F_i(x)&=\frac{1}{x-1}\sum\limits_{j}\frac{x^{j+1}-1}{j+1}[x^j]F_{i-1}(x)\\&=\frac{1}{x-1}\sum\limits_j[x^j]F_{i-1}(x)\int_1^xt^jdt\\&=\frac{1}{x-1}\int_1^x\left(\sum\limits_{j}[x^j]F_{i-1}(x)t^j\right)dt\\&=\frac{1}{x-1}\int_1^xF_{i-1}(t)dt\end{aligned} \]

这个积分的下限为 \(1\),尝试换元转不定积分。令 \(z=x-1\)

\[\begin{aligned}F_i(x)&=F_i(z+1)\\&=\frac{1}{z}\int _0^{z}F_{i-1}(t+1)d(t+1)\end{aligned} \]

再次换元,令 \(G_i(x)=F_i(x+1)\)

\[\begin{aligned}G_i(x)&=\frac{1}{x}\int_0^zG_{i-1}(t)dt\\&=\frac{1}{x}\int G_{i-1}(z)dz \\&=\frac{1}{x}\sum\limits_j[x^j]G_{i-1}(x)\frac{x^{j+1}}{j+1}\\&=\sum\limits_j[x^j]G_{i-1}(x)\frac{x^j}{j+1}\end{aligned} \]

比较左右系数,得到 \([x^j]G_{i}(x)=\frac{[x^j]G_{i-1}(x)}{j+1}\),这是个等比数列,于是 \([x^j]G_i(x)=(i+1)^{-j}[x^j]G_0(i)\),现在考虑如何快速求出 \(G(x)=G_0(x)=F(x+1)\)

\[\begin{aligned}G(x)&=F(x+1)\\&=\sum\limits_{i}[x^i]F(x)(x+1)^i\\&=\sum\limits_i[x^i]F(x)\sum\limits_{j=0}^i\dbinom{i}{j}x_j\\&=\sum\limits_{j}x^j\sum\limits_{i=j}[x^i]F(x)\dbinom{i}{j}\end{aligned} \]

提取 \(G(x)\) 的系数:

\[\begin{aligned}[x^j]G(x)&=\sum\limits_{i=j}[x^i]F(x)\dbinom{i}{j}\\&=\sum\limits_{i=j}\frac{i!}{j!(i-j)!}[x^i]F(x)\\&=\frac{1}{j!}\sum\limits_{i=j}i![x^i]F(x)\cdot \frac{1}{(i-j)!}\end{aligned} \]

这就变成了显然的差卷积形式,直接做就行了。

得到 \(G_n(x)\) 之后,就可以二项式反演得到 \(F_n(x)\)

\[\begin{aligned}[x^j]G_m(x)&=\sum\limits_{i=j}[x^i]F_m(x)\dbinom{i}{j}\end{aligned} \]

\[\begin{aligned}[x^j]F_m(x)&=\sum\limits_{i=j}[x^i]G_m(x)(-1)^{i-j}\dbinom{i}{j}\end{aligned} \]

同样的套路,拆开组合数即可。

复杂度 \(O(n\log n)\)

// Problem: E. Perpetual Subtraction
// Contest: Codeforces - VK Cup 2018 - Round 1
// URL: https://codeforces.com/problemset/problem/923/E
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;

namespace vbzIO {
    char ibuf[(1 << 20) + 1], *iS, *iT;
    #if ONLINE_JUDGE
    #define gh() (iS == iT ? iT = (iS = ibuf) + fread(ibuf, 1, (1 << 20) + 1, stdin), (iS == iT ? EOF : *iS++) : *iS++)
    #else
    #define gh() getchar()
    #endif
    #define mt make_tuple
    #define mp make_pair
    #define fi first
    #define se second
    #define pc putchar
    #define pb emplace_back
    #define ins insert
    #define era erase
    typedef long long ll;
    typedef tuple<int, int, int> tu3;
    typedef pair<int, int> pi;
    inline int rd() {
        char ch = gh();
        int x = 0;
        bool t = 0;
        while (ch < '0' || ch > '9') t |= ch == '-', ch = gh();
        while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = gh();
        return t ? ~(x - 1) : x;
    }
    inline ll rdl() {
        char ch = gh();
        ll x = 0;
        bool t = 0;
        while (ch < '0' || ch > '9') t |= ch == '-', ch = gh();
        while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = gh();
        return t ? ~(x - 1) : x;
    }
    inline void wr(int x) {
        if (x < 0) x = ~(x - 1), putchar('-');
        if (x > 9) wr(x / 10);
        putchar(x % 10 + '0');
    }
}
using namespace vbzIO;

const int P = 998244353;
const int N = 5e5 + 500;
const int G = 114514;

int n, m, len, lim;
int f[N], g[N], fac[N], ifac[N], inv[N], tr[N];

int Add(int x, int y) { x += y; return (x >= P) ? (x - P) : x; }
int Mul(int x, int y) { return 1ll * x * y % P; }

int qpow(int p, int q) {
	int res = 1;
	for (; q; q >>= 1, p = Mul(p, p))
		if (q & 1) res = Mul(res, p);
	return res;
}

const int iG = qpow(G, P - 2);

void init(int lim) {
	fac[0] = ifac[0] = inv[1] = 1;
	for (int i = 1; i <= lim; i++) {
		if (i > 1) inv[i] = Mul(inv[P % i], P - P / i);
		fac[i] = Mul(fac[i - 1], i), ifac[i] = Mul(ifac[i - 1], inv[i]);
	}
}

int C(int n, int m) {
	if (n < m || m < 0) return 0;
	return Mul(fac[n], Mul(ifac[m], ifac[n - m]));
}

void NTT(int *f, int op) {
	for (int i = 0; i < len; i++)
		if (i < tr[i]) swap(f[i], f[tr[i]]);
	for (int o = 2, k = 1; k < len; o <<= 1, k <<= 1) {
		int tg = qpow(~op ? G : iG, (P - 1) / o);
		for (int i = 0; i < len; i += o) {
			for (int j = 0, w = 1; j < k; j++, w = Mul(w, tg)) {
				int x = f[i + j], y = Mul(w, f[i + j + k]);
				f[i + j] = Add(x, y), f[i + j + k] = Add(x, P - y);
			}
		}
	}
	if (~op) return;
	int iv = qpow(len, P - 2);
	for (int i = 0; i < len; i++)
		f[i] = Mul(f[i], iv);
}

void Mul(int *f, int *g, int *h) {
	static int tf[N], tg[N];
	len = 1, lim = 0;
	while (len < (n + 1) << 1) len <<= 1, lim++;
	for (int i = 1; i < len; i++)
		tr[i] = (tr[i >> 1] >> 1) | ((i & 1) << (lim - 1));
	for (int i = 0; i <= n; i++) tf[i] = f[i], tg[i] = g[i];
	for (int i = n + 1; i < len; i++) tf[i] = tg[i] = 0;
	NTT(tf, 1), NTT(tg, 1);
	for (int i = 0; i < len; i++)
		tf[i] = Mul(tf[i], tg[i]);
	NTT(tf, -1);
	for (int i = 0; i <= n; i++) h[i] = tf[i];
}

int main() {
    n = rd(), m = rdl() % (P - 1), init(n);
    for (int i = 0; i <= n; i++) 
		f[i] = Mul(rd(), fac[i]);
    reverse(f, f + n + 1);
    for (int i = 0; i <= n; i++) 
    	g[i] = ifac[i];
    Mul(f, g, g);
    reverse(g, g + n + 1);
    for (int i = 0; i <= n; i++)
    	g[i] = Mul(g[i], ifac[i]);
    for (int i = 0; i <= n; i++)
    	g[i] = Mul(g[i], qpow(qpow(i + 1, P - 2), m));
	for (int i = 0; i <= n; i++)
		g[i] = Mul(g[i], fac[i]);
    reverse(g, g + n + 1);
    for (int i = 0; i <= n; i++)
    	f[i] = Mul(((i & 1) ? (P - 1) : 1), ifac[i]);
    Mul(f, g, f);
    reverse(f, f + n + 1);
    for (int i = 0; i <= n; i++)
    	wr(Mul(f[i], ifac[i])), pc(' ');
    return 0;
}