我是靠谱客的博主 粗心自行车,这篇文章主要介绍【JSOI 2012】分零食(倍增 + FFT),现在分享给大家,希望可以做个参考。

题目链接:【JSOI 2012】分零食

题目大意:将 m m 颗糖依次分给 n 个小朋友,每个小朋友的快乐度为 f(x=)=ox2+sx+u f ( x = 得 到 的 糖 果 数 ) = o x 2 + s x + u 。特别地, f(0)=1 f ( 0 ) = 1 。糖果分完后剩下的小朋友将得不到糖果。求每种情况下小朋友快乐度乘积之和 mod998244353 mod 998244353 的结果。

g[i][j] g [ i ] [ j ] 表示前 i i 个小朋友得到 j 颗糖的答案。则: g[i][j]=jk=1f(jk)g[i1][k] g [ i ] [ j ] = ∑ k = 1 j f ( j − k ) g [ i − 1 ] [ k ] 。发现这是个卷积的形式。想到 FFT F F T ,发现 g[n]=fn g [ n ] = f n

A[n]=nj=1g[i] A [ n ] = ∑ j = 1 n g [ i ] 。我们使用倍增的方法求出 A[n] A [ n ]


A[n+1]=n+1i=1g[i] A [ n + 1 ] = ∑ i = 1 n + 1 g [ i ]
A[n+1]=A[n]+g[n+1] A [ n + 1 ] = A [ n ] + g [ n + 1 ]

A[2n]=2ni=1g[i] A [ 2 n ] = ∑ i = 1 2 n g [ i ]
A[2n]=A[n]+2ni=n+1g[i] A [ 2 n ] = A [ n ] + ∑ i = n + 1 2 n g [ i ]
A[2n]=A[n]+fnni=1fi A [ 2 n ] = A [ n ] + f n ∑ i = 1 n f i
A[2n]=A[n]+g[n]A[n] A [ 2 n ] = A [ n ] + g [ n ] ∗ A [ n ]


然后用 FFT F F T 做卷积即可。

复制代码
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <cmath> #include <cstdio> #include <complex> #include <iostream> using namespace std; typedef complex<double> cd; const double pi = acos(-1.); const int maxn = 1 << 15 | 5; cd f[maxn], g[maxn], dp[maxn], tmp[maxn]; int n, m, o, s, u, mod, lim, bit, r[maxn]; void fft(cd *a, int dft) { for (int i = 0; i < lim; i++) { if (i < r[i]) { swap(a[i], a[r[i]]); } } for (int k = 1; k < lim; k <<= 1) { cd wn0(cos(pi / k), dft * sin(pi / k)); for (int i = 0; i < lim; i += k << 1) { cd wnk(1, 0); for (int j = i; j < i + k; j++, wnk *= wn0) { cd x = a[j], y = wnk * a[j + k]; a[j] = x + y, a[j + k] = x - y; } } } if (dft == -1) { for (int i = 0; i < lim; i++) { a[i] /= lim; a[i] = int(a[i].real() + 0.5) % mod; } } } void solve(cd *dp, cd *g, int n) { if (!n) { g[0] = 1; return; } if (n & 1) { solve(dp, g, n - 1); fft(g, 1); for (int i = 0; i < lim; i++) { g[i] *= f[i]; } fft(g, -1); for (int i = 0; i <= m; i++) { dp[i] += g[i]; dp[i] = int(dp[i].real() + 0.5) % mod; } for (int i = m + 1; i < lim; i++) { g[i] = 0; } } else { solve(dp, g, n >> 1); for (int i = 0; i < lim; i++) { tmp[i] = dp[i]; } fft(tmp, 1); fft(g, 1); for (int i = 0; i < lim; i++) { tmp[i] *= g[i]; } fft(tmp, -1); for (int i = 0; i < lim; i++) { g[i] *= g[i]; } fft(g, -1); for (int i = 0; i <= m; i++) { dp[i] += tmp[i]; dp[i] = int(dp[i].real() + 0.5) % mod; } for (int i = m + 1; i < lim; i++) { g[i] = 0; } } } int main() { scanf("%d %d", &m, &mod); scanf("%d", &n); scanf("%d", &o); scanf("%d", &s); scanf("%d", &u); for (lim = 1; lim <= 2 * m; lim <<= 1) bit++; for (int i = 0; i < lim; i++) { r[i] = (r[i >> 1] >> 1) | ((i & 1) << (bit - 1)); } for (int i = 1; i <= m; i++) { f[i] = (o * i * i + s * i + u) % mod; } fft(f, 1); solve(dp, g, n); printf("%dn", int(dp[m].real() + 0.5)); return 0; }

最后

以上就是粗心自行车最近收集整理的关于【JSOI 2012】分零食(倍增 + FFT)的全部内容,更多相关【JSOI内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(63)

评论列表共有 0 条评论

立即
投稿
返回
顶部