[LOJ 6485]LJJ 学二项式定理

[LOJ 6485] LJJ 学二项式定理

题意

给定 \(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\).

题解

一看 \(n\) 巨大无比显然不太能直接搞.

但是这个 \(\bmod 4\) 十分的玄妙, 我们尝试从它入手, 分别计算每个 \(a_i\) 所产生的贡献.

又因为组合数越界会变 \(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]\) 反演掉就好了.

幸运的是在傅立叶变换中有个东西叫求和引理, 即当 \(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} \]
然后就可以算了.

参考代码

其实 \(\omega_4\) 就是虚数单位 \(i\)...

#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;
}

猜你喜欢

转载自www.cnblogs.com/rvalue/p/11011699.html