VK Cup 2018 - Round 1 E Perpetual Subtraction

题目描述

http://codeforces.com/problemset/problem/923/E

简要题意:你现在有一个整数 $x$,题目给出它属于 $[0,n]$ 中某个数的概率,现在要进行 $m$ 次随机,每次随机将等概率的将 $x$ 变成 $[0,x]$ 中的任意一个整数,求 $m$ 次操作后,整数 $x=k$,其中 $k\in[0,n]$ 的概率

$n\le 10^5,m\le 10^{18}$

Solution

我们令 $f_{k,i}$ 表示进行了 $k$ 次随机之后为 $i$ 的概率,容易得到 $f_{k,i}=\sum_{j=i}^n\frac{f_{k-1,j}}{j+1}$,发现这个东西是一个线性变换,尝试用生成函数搞一下,我们将其写成生成函数的形式,得到 $F_{k}(x)=\sum_{i=0}^nf_{k,i}x^i$,然后尝试化简一下

现在似乎有点眉目了,但是这个 $\frac{1}{x-1}$ 和这个从 $1$ 积到 $x$ 的积分不是很好应对,我们令 $G_{k}(x)=F_{k}(x+1)$,然后在带进这个式子里去,$G_{k}(x)=\frac{1}{x}\int_{1}^{x+1}F_{k-1}(t)\rm dt=\frac{1}{x}\int_{0}^xF_{k-1}(t+1)\rm dt$,我们注意到 $G_{k-1}(x)=F_{k-1}(x+1)$,那么我们就能得到 $G_k(x)=\frac{1}{x}\int_{0}^xG_{k-1}(x)\rm dt=\sum_{i=0}^n\frac{1}{i+1}g_{k-1,i}x^i$,也就是说 $g_{k,i}=\frac{1}{(i+1)^k}g_{0,i}$,然后我们只需要求一下 $F_0(x)$ 到 $G_0(x)$ 的转换和 $G_m(x)$ 到 $F_m(x)$ 的转换,推一下能发现都是一个差卷积的形式,时间复杂度 $O(n\log n)$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <iostream>
#include <vector>
#include <algorithm>
#define maxn 100010
#define ll long long
using namespace std;

const int p = 998244353;

ll pow_mod(ll x, ll n) {
ll s = 1;
for (; n; n >>= 1, x = x * x % p)
if (n & 1) s = s * x % p;
return s;
}

typedef std::vector<int> Poly;
namespace Pol {
inline int add(int a, int b) { return (a += b) >= p ? a -= p : a; }
inline int mul(int a, int b) { return 1ll * a * b % p; }

const int N = 4200000;
int a[N], b[N];

int P[N];
void init_P(int n) {
int l = 0; while ((1 << l) < n) ++l;
for (int i = 0; i < n; ++i) P[i] = (P[i >> 1] >> 1) | ((i & 1) << l - 1);
}
void NTT(int *a, int n, int type) {
static int w[N]; ll G = 3, Gi = pow_mod(G, p - 2);
for (int i = 0; i < n; ++i) if (i < P[i]) swap(a[i], a[P[i]]);
for (int i = 2, m = 1; i <= n; m = i, i *= 2) {
int wn = pow_mod(type > 0 ? G : Gi, (p - 1) / i);
w[0] = 1; for (int j = 1; j < m; ++j) w[j] = mul(wn, w[j - 1]);
for (int j = 0; j < n; j += i)
for (int k = 0; k < m; ++k) {
int t1 = a[j + k], t2 = mul(a[j + k + m], w[k]);
a[j + k] = add(t1, t2);
a[j + k + m] = add(t1, p - t2);
}
}
if (type < 0) {
ll inv = pow_mod(n, p - 2);
for (int i = 0; i < n; ++i) a[i] = inv * a[i] % p;
}
}
Poly Mul(const Poly &A, const Poly &B, int n1, int n2) {
int n = 1; while (n < n1 + n2 - 1) n <<= 1; init_P(n);
for (int i = 0; i < n1; ++i) a[i] = add(A[i], p);
for (int i = 0; i < n2; ++i) b[i] = add(B[i], p);
fill(a + n1, a + n, 0), fill(b + n2, b + n, 0);
NTT(a, n, 1); NTT(b, n, 1);
for (int i = 0; i < n; ++i) a[i] = mul(a[i], b[i]);
NTT(a, n, -1); Poly ans(n1 + n2 - 1); copy_n(a, n1 + n2 - 1, ans.begin());
return ans;
}
} // namespace Pol

int n;
ll m, fac[maxn], inv[maxn];

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);

cin >> n >> m; ++n; Poly A(n), B(n);
fac[0] = 1; for (int i = 1; i <= n; ++i) fac[i] = fac[i - 1] * i % p;
inv[n] = pow_mod(fac[n], p - 2); for (int i = n - 1; ~i; --i) inv[i] = inv[i + 1] * (i + 1) % p;
for (int i = 0; i < n; ++i) cin >> A[i], A[i] = A[i] * fac[i] % p;
for (int i = 0; i < n; ++i) B[i] = inv[i];
reverse(A.begin(), A.end()); A = Pol::Mul(A, B, n, n); A.resize(n); reverse(A.begin(), A.end());
for (int i = 0; i < n; ++i) A[i] = A[i] * inv[i] % p * pow_mod(pow_mod(i + 1, m), p - 2) % p;
for (int i = 0, sgn = 1; i < n; ++i, sgn = -sgn) A[i] = A[i] * sgn * fac[i] % p;
reverse(A.begin(), A.end()); A = Pol::Mul(A, B, n, n); A.resize(n); reverse(A.begin(), A.end());
for (int i = 0, sgn = 1; i < n; ++i, sgn = -sgn)
cout << (A[i] * sgn * inv[i] % p + p) % p << " \n"[i == n - 1];
return 0;
}