給定 \(n,s,a_0,a_1,a_2,a_3\), 求:
\[ \Large \left[ \sum_{i=0}^n \left( {n\choose i} \cdot s^{i} \cdot a_{i\bmod 4} \right) \right] \bmod 998244353 \]
\(T\le 10^5\) 組測試數據, \(n\le 10^{18};s,a_i\le 10^9\).c++
一看 \(n\) 巨大無比顯然不太能直接搞.測試
可是這個 \(\bmod 4\) 十分的玄妙, 咱們嘗試從它入手, 分別計算每一個 \(a_i\) 所產生的貢獻.spa
又由於組合數越界會變 \(0\), 因而答案能夠寫成這樣:
\[ \sum_{k=0}^3\sum_{i\bmod 4=k} {n\choose i}a_ks^i \]
\(i\bmod 4=k\) 等價於 \(4\mid i-k\). 因而咱們有:
\[ \sum_{k=0}^3\sum_{4\mid i-k} {n\choose i}a_ks^i \]
把下標換漂亮點而且把求和條件變成布爾表達式丟到和式裏:
\[ \sum_{k=0}^3\sum_{i}[4\mid i] {n\choose i+k}a_ks^{i+k} \]
而後咱們若是能找個東西把 \([4\mid i]\) 反演掉就行了.3d
幸運的是在傅立葉變換中有個東西叫求和引理, 即當 \(k\not \mid n\) 的時候有:
\[ \sum_{j=0}^{n-1}(\omega_n^k)^j=0 \]
不難算出當 \(k\mid n\) 的時候上式的值爲 \(n\). 也就是說:
\[ \frac 1 n\sum_{j=0}^{n-1}(\omega_n^k)^j=\frac 1 n\sum_{j=0}^{n-1}\omega_n^{kj}=[k\mid n] \]
那麼咱們就能夠把這個東西代進去按照和式的套路搞一搞求和順序和指標:
\[ \begin{aligned} &\sum_{k=0}^3\sum_{i}\left (\frac 1 4\sum_{r=0}^3\omega_4^{ir}\right) {n\choose i+k}a_ks^{i+k}\\ =&\frac 1 4\sum_{k=0}^3\sum_{r=0}^3a_k\sum_{i}{n\choose i+k}s^{i+k}\omega_4^{ir} \\ \end{aligned} \]
那麼問題變成了最內層的東西. 咱們發現它有點相似二項式定理的形式, 可是 \(\omega_4^r\) 上的指數不太對. 咱們強行讓它和二項式係數的部分同樣:
\[ \begin{aligned} &\frac 1 4\sum_{k=0}^3\sum_{r=0}^3a_k\sum_{i}{n\choose i+k}s^{i+k}\omega_4^{(i+k)r}\omega_4^{-kr} \\ =&\frac 1 4\sum_{k=0}^3\sum_{r=0}^3a_k\omega_4^{-kr} \sum_{i}{n\choose i+k}s^{i+k}\omega_4^{(i+k)r}\\ =&\frac 1 4\sum_{k=0}^3\sum_{r=0}^3a_k\omega_4^{-kr} \sum_{i}{n\choose i+k}(s\omega_4^r)^{i+k} \\ =&\frac 1 4\sum_{k=0}^3\sum_{r=0}^3a_k\omega_4^{-kr} (s\omega_4^r+1)^n \end{aligned} \]
而後就能夠算了.code
其實 \(\omega_4\) 就是虛數單位 \(i\)...blog
#include <bits/stdc++.h> const int I=911660635; const int NI=86583718; const int MOD=998244353; const int PHI=998244352; const int INV4=748683265; typedef long long intEx; int Pow(int,int,int); int main(){ int T; scanf("%d",&T); while(T--){ intEx n; int s; scanf("%lld%d",&n,&s); int ans=0; for(int i=0;i<4;i++){ int a; scanf("%d",&a); for(int j=0;j<4;j++) (ans+=1ll*a*Pow(NI,i*j,MOD)%MOD*Pow((1ll*Pow(I,j,MOD)*s+1)%MOD,n%PHI,MOD)%MOD)%=MOD; } ans=1ll*ans*INV4%MOD; printf("%d\n",ans); } return 0; } inline int Pow(int a,int n,int p){ int ans=1; while(n>0){ if(n&1) ans=1ll*a*ans%p; a=1ll*a*a%p; n>>=1; } return ans; }