单位根反演
单位根反演是拿来做([kmod m=0,1,dots,m-1])这样的余数条件判别式的一种展开方法。
这类题通常(m)很小,可以枚举,并且模数具有(m)次单位根。
单位根反演主要运用的是如下的等式(快速傅里叶变换的理论的一部分)
[[kmod m=0]=frac{1}{m}sum_{i=0}^{m-1}(omega_m^k)^i
]
分类讨论证明:
-
(kmod m=0),那么(omega_m^k=1),变成简单加法。
[frac{1}{m}sum_{i=0}^{m-1}(omega_m^k)^i=frac{1}{m}sum_{i=0}^{m-1}1^i=1 ] -
(kmod m eq 0),那么(omega_m^k eq 1),变成等比数列求和。
[frac{1}{m}sum_{i=0}^{m-1}(omega_m^k)^i=frac{1}{m}frac{omega_m^0-(omega_m^k)^m}{1-omega_m^k}=0 ]
令(F(x)=sum_{i=0}^nf_ix^i),现在我们要求(sum_{i=0}^nf_i[imod m=0]),那么考虑如下计算式
[frac{1}{m}sum_{i=0}^{m-1}F(omega_{m}^i)=frac{1}{m}sum_{j=0}^{m-1}sum_{i=0}^nf_i(omega_m^j)^i\
=sum_{i=0}^nf_ifrac{1}{m}sum_{j=0}^{m-1}(omega_m^i)^j\
=sum_{i=0}^nf_i[imod m=0]
]
那么对于一般情况,如果我们要求(sum_{i=0}^nf_i[imod m=a])又该怎么做呢?对(frac{F(x)}{x^a})做相同的事情即可。
LJJ学二项式定理
LJJ学完了二项式定理,发现这太简单了,于是他将二项式定理等号右边的式子修改了一下,代入了一定的值,并算出了答案。
但人口算毕竟会失误,他请来了你,让你求出这个答案来验证一下。
一共有(T)组数据,每组数据如下:
输入以下变量的值:(n, s, a_0, a_1, a_2, a_3),求以下式子的值:
[sum_{i=0}^n inom{n}{i} cdot s^{i} cdot a_{imod 4}mod 998244353
]
对于(100\%)的数据,(1 leq T leq 10^5, 1 leq n leq 10 ^ {18}, 1 leq s, a_0, a_1, a_2, a_3 leq 10^{8})。
题解
[ ext{ans}=sum_{j=0}^3a_jsum_{i=0}^ninom{n}{i}s^i[imod 4=j]
]
令(F(x)=sum_{i=0}^ninom{n}{i}s^ix^i=(sx+1)^n),然后单位根反演即可。
[ ext{ans}=sum_{j=0}^3a_jfrac{1}{4}sum_{i=0}^3frac{F(omega_4^i)}{(omega_4^i)^j}
]
这破题还卡常……必须要预处理,不然会有16倍的常数。
array<int,4> w,iw;
void real_main(){
int n=read<int64>()%(mod-1),s=read<int>();
function<int(int)> F=[&](int x)->int{
return fpow(mul(s,x)+1,n);
};
array<int,4> a,f;
for(int i=0;i<4;++i){
read(a[i]);
f[i]=F(w[i]);
}
int ans=0;
for(int j=0;j<4;++j)for(int i=0;i<4;++i)
ans=add(ans,mul(a[j],mul(f[i],fpow(iw[i],j))));
ans=mul(ans,fpow(4,mod-2));
printf("%d
",ans);
}
int main(){
for(int i=0;i<4;++i){
w[i]=fpow(3,(mod-1)/4*i);
iw[i]=fpow(w[i],mod-2);
}
for(int T=read<int>();T--;) real_main();
return 0;
}