给定 \(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; }