[LOJ 6485]LJJ学二项式定理(单位根反演)

也许更好的阅读体验
(mathcal{Description})

原题链接

(T)组询问,每次给(n,s,a_0,a_1,a_2,a_3)
(egin{aligned}left(sum ^{n}_{i=0}egin{pmatrix} n \ i end{pmatrix}cdot s^{i}cdot a_{i mod 4} ight)mod 998244353end{aligned})

(mathcal{Solution})

这道题要用单位根反演
(egin{aligned}left[ n | k ight] =dfrac {1}{n}sum ^{n-1}_{i=0}w^{ik}_{n}end{aligned})

我们先打表,或者查表找出在模(998244353)下的原根(omega_4^0)并处理好(omega_4^1,omega_4^2,omega_4^3)
考虑对每个(a_i)单独计算其答案
(a_0)为例
(egin{aligned} ans_{a_0}&=frac{1}{4}a_0sum_{i=0}^n [4 | i]{nchoose i}s^i\ &=frac{1}{4}a_0sum_{i=0}^n{nchoose i}s^isum_{j=0}^3 (omega_4^{j})^i\ &=frac{1}{4}a_0sum_{j=0}^3sum_{i=0}^n {nchoose i}s^i(omega_4^j)^i\ &=frac{1}{4}a_0sum_{j=0}^3(somega_4^j+1)^n end{aligned})

对于其他(a_i),我们可以将其写成([4 | i+4-k])的形式,并提一个(omega^x)出来
下面完整的推一遍

(egin{aligned}ans&=sum ^{3}_{k=0}a_{k}sum ^{n}_{i=0}left[ 4 | i+4-k ight] s^{i}cdot egin{pmatrix} n \ i end{pmatrix}\ &=sum ^{3}_{k=0}dfrac {1}{4}a_{k}sum ^{n}_{i=0}sum ^{3}_{j=0}omega^{jcdotleft( i+4-k ight) }_{4}cdot s^{i}cdot egin{pmatrix} n \ i end{pmatrix}\ &=sum ^{3}_{k=0}dfrac {1}{4}a_{k}sum ^{n}_{i=0}sum ^{3}_{j=0}omega^{left(4j-jk ight) }_{4}cdot omega^{j^i}_4cdot s^{i}cdot egin{pmatrix} n \ i end{pmatrix}\ &=sum ^{3}_{k=0}dfrac {1}{4}a_{k}sum ^{3}_{j=0}omega^{left(4j-jk ight) }_{4}sum ^{n}_{i=0} omega^{j^i}cdot s^{i}cdot egin{pmatrix} n \ i end{pmatrix}\ &=sum ^{3}_{k=0}dfrac {1}{4}a_{k}sum ^{3}_{j=0}omega^{left(4j-jk ight) }_{4}left(scdot omega^j_4+1 ight)^n \ end{aligned})
拿出来,再写一遍
(egin{aligned}ans=sum ^{3}_{i=0}dfrac {1}{4}a_{i}sum ^{3}_{j=0}omega^{left(4j-ij ight) }_{4}left(scdot omega^j_4+1 ight)^n \ end{aligned})

(mathcal{Code})

#include <cstdio>
#define ll long long
using namespace std;
const int mod = 998244353;
const int w [] = {1,911660635,998244352,86583718};
ll T,n,s,ans,res,inv;
ll a[4];
ll ksm (ll a,ll b)
{
	a%=mod;
	ll s=1;
	for (;b;b>>=1,a=a*a%mod)
		if (b&1)	s=s*a%mod;
	return s;
}
int main ()
{
	scanf("%lld",&T);
	inv=ksm(4,mod-2);
	while (T--){
		scanf("%lld%lld%lld%lld%lld%lld",&n,&s,&a[0],&a[1],&a[2],&a[3]);
		ans=0;
		for (int i=0;i<=3;++i){
			res=0;
			for (int j=0;j<=3;++j)
				res=(res+w[(4*j-i*j)%4]*ksm(s*w[j]+1,n)%mod)%mod;
			ans=(ans+a[i]*res%mod)%mod;
		}
		printf("%lld
",ans*inv%mod);
	}
	return 0;
}

如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧

原文地址:https://www.cnblogs.com/Morning-Glory/p/11322135.html