loj #6485. LJJ 学二项式定理
给定$n,s,a_0,a_1,a_2,a_3$,求
$$\sum_{i=0}^{n} {n \choose i} s^i a_{i \bmod 4}$$
答案对$998244353$取模
$1 \le n \le 10^{18}, 1 \le s,a_0,a_1,a_2,a_3 \le 10^8$
一脸绝望
在高中的时候,数学老师教会了我们$(a+b)^{n}=\sum_{i=0}^{n}{n \choose i}a^{i}b^{n-i}$,然后惊喜的发现这道题不能这么做!
在$OI$中,我们学习了单位根的基本性质,关于单位根还有一个迷之用法——单位根反演
对于数列$a_i$,构造其生成函数$f(x)=\sum_{i=0}^{n}a_ix^i$
现在我们想知道所有下标是$k$的倍数的$a_i$的和,既$\sum_{i=0}^{n}a_i[k|i]$
有一个关于$n$次单位根$w_n$的等式,看起来十分有趣毒瘤
$$[n|k]=\frac{1}{n}\sum_{i=0}^{n-1}\omega_n^{ki}$$
证明:
如果$n \mid k$,设$k=np$,则
$$\frac{1}{n}\sum_{i=0}^{n-1}w_n^{npi \bmod n}=\frac{1}{n}\sum_{i=0}^{n-1}w_n^{0}=1$$
如果$n \nmid k$,根据等比数列求和公式,则
$$\frac{1}{n}\sum_{i=0}^{n-1}\omega_{n}^{ki}=\frac{1}{n}(w_n^{0}\frac{1-\omega_n^{k(n-1)}}{1-w_n^{k}})=\frac{w_n^0-w_n^{kn}}{n(1-\omega_n^{k})}=0$$
于是对于$N$次单位根$w_N$可以这么搞:
$$\frac{\sum_{i=0}^{N-1}f(w_N^i)}{N}=\frac{\sum_{i=0}^{n}a_i\sum_{j=0}^{N-1}w_N^{ij}}{N}=\sum_{i=0}^{n}a_i[N \mid i]$$
于是就可以得到所有下标是$N$的倍数的$a_i$的和了
但是发现,只知道所有$N \mid i$的$a_i$的和还不够有用,如果分别知道$i \bmod N \in [0,N-1]$的$a_i$的和的话就十分有用了
数学老师告诉我们,$f(x)$通过乘以$x$的若干次幂可以实现函数的平移(虽然说这句话不太严谨……但还是可以凑合着看看……)
比如说现在有$f(x)=a_0x^{0}+a_1x^{1}+a_2x^{2} + \dots$
对其乘上$x^{-1}$后会得到$f(x)x^{-1}=a_0x^{-1}+a_1x^{0}+a_2x^{1} + \dots$
再用上面的方法求后就得到了$N \bmod i = 1$的所有$a_i$和
在这道题中,构造$f(x)=\sum_{i=0}^{n} {n \choose i} s^i x^i 1^{n-i}=(sx+1)^n$
则答案为$\sum_{i=0}^{3}a_ic_i$,其中$c_i=\sum\limits_{j=0}^{n}{n \choose j}s^j[j \bmod 4 = i]$
对于$c_i$的$f(\omega_N^j)$,因为需要将$\omega_N^{j}$向右平移$i$次,只需要将其变为$\huge \frac{f(\omega_N^j)}{\omega_N^{ij \bmod 4}}$即可
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int p = 998244353, g = 3; 5 ll pw(ll a, ll b) { 6 ll r = 1; 7 for( ; b ; b >>= 1, a = a * a % p) if(b & 1) r = r * a % p; 8 return r; 9 } 10 ll n, s, a[4], w[4], c[4]; 11 int main() { 12 int T; scanf("%d", &T); 13 ll wn = pw(g, (p - 1) / 4), inv4 = pw(4, p - 2); 14 w[0] = 1; for(int i = 1 ; i < 4 ; ++ i) w[i] = w[i - 1] * wn % p; 15 while(T --) { 16 scanf("%lld%lld", &n, &s); 17 for(int i = 0 ; i < 4 ; ++ i) scanf("%lld", &a[i]), c[i] = 0; 18 for(int i = 0 ; i < 4 ; ++ i) { 19 for(int j = 0 ; j < 4 ; ++ j) 20 c[i] = (c[i] + pw((1 + w[j] * s % p) % p, n) * pw(w[i * j % 4], p - 2) % p) % p; 21 c[i] = c[i] * inv4 % p; 22 } 23 ll sum = 0; 24 for(int i = 0 ; i < 4 ; ++ i) sum = (sum + a[i] * c[i] % p) % p; 25 printf("%lld\n", sum); 26 } 27 }
一些资料
shadowice1984 loj6485 LJJ学二项式定理