#单位根反演,二项式定理#LOJ 6485 LJJ 学二项式定理
作者:互联网
题目
\[\large\sum_{i=0}^nC(n,i)S^ia_{i\bmod 4} \]\(n\leq 10^{18},S,a\leq 10^8\)
分析
前面这一坨看起来就像是二项式定理,考虑如何把后面这一坨弄掉
\[\large=\sum_{i=0}^nC(n,i)S^i\sum_{j=0}^3a_j[i\bmod 4==j] \]由于\([i\bmod 4==j]\)等同于\([4|(i-j)]\)
\[\large=\frac{1}{4}\sum_{i=0}^nC(n,i)S^i\sum_{j=0}^3a_j\sum_{k=0}^3\omega_4^{k(i-j)} \]把有关\(j\)的项挪到前面去,就是
\[\large=\frac{1}{4}\sum_{j=0}^3a_j\sum_{k=0}^3-\omega_4^{jk}\sum_{i=0}^nC(n,i)S^i\omega_4^{ki} \]\[\large=\frac{1}{4}\sum_{j=0}^3a_j\sum_{k=0}^3-\omega_4^{jk}(S\omega_4^k+1)^n \]直接预处理单位根就可以了
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int mod=998244353; int pw[4];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline signed ksm(int x,int y){
rr int ans=1;
for (;y;y>>=1,x=1ll*x*x%mod)
if (y&1) ans=1ll*ans*x%mod;
return ans;
}
inline signed mo(int x,int y){return x+y>=mod?x+y-mod:x+y;}
signed main(){
pw[0]=1,pw[1]=ksm(3,(mod-1)/4);
for (rr int i=2;i<4;++i)
pw[i]=1ll*pw[i-1]*pw[1]%mod;
rr int inv4=ksm(4,mod-2);
for (rr int T=iut();T;--T){
rr long long n; scanf("%lld",&n);
n%=mod-1; rr int m=iut(),ans=0;
for (rr int i=0;i<4;++i){
rr int x=iut(),sum=0;
for (rr int j=0;j<4;++j)
sum=mo(sum,1ll*pw[(4-i*j%4)%4]*ksm(1ll*m*pw[j]%mod+1,n)%mod);
ans=mo(ans,1ll*sum*x%mod);
}
print(1ll*ans*inv4%mod),putchar(10);
}
return 0;
}
标签:rr,int,定理,单位根,ans,二项式,omega,sum,mod 来源: https://www.cnblogs.com/Spare-No-Effort/p/14975161.html