【LOJ6485】LJJ 学二项式定理(单位根反演)

传送门


题解:

我们要求的是这个东西:
A n s = ∑ i = 0 n ( n i ) s i ⋅ a i % 4 Ans=\sum_{i=0}^n{n\choose i}s^i\cdot a_{i\%4} Ans=i=0n(in)siai%4

首先我们有单位根的性质: [ n ∣ k ] = 1 n ∑ i = 0 n − 1 ω n i k [n\mid k]=\frac{1}{n}\sum_{i=0}^{n-1}\omega_{n}^{ik} [nk]=n1i=0n1ωnik

我们考虑求一个数列 { a } \{a\} {a}的所有 k k k的倍数项之和。令其生成函数为 A ( x ) = ∑ i = 0 n a i x i A(x)=\sum\limits_{i=0}^{n} a_ix^i A(x)=i=0naixi

那么我们有 ∑ i = 0 n a i [ k ∣ i ] = 1 k ∑ i = 0 k − 1 A ( ω k i ) \sum_{i=0}^{n} a_i[k\mid i]=\frac{1}{k}\sum_{i=0}^{k-1}A(\omega_{k}^i) i=0nai[ki]=k1i=0k1A(ωki)

如果 A ( ω k i ) A(\omega_{k}^i) A(ωki)有什么快速计算方式的话就可以优化复杂度了。

以上就是单位根反演的理论基础。

在这道题中我们先将上面的式子进行一点转化:

A n s = ∑ d = 0 3 a d ∑ i = 0 n ( n i ) s i [ i % 4 = d ] Ans=\sum_{d=0}^3a_d\sum_{i=0}^n{n\choose i}s^i[i\%4=d] Ans=d=03adi=0n(in)si[i%4=d]

先不管那个 d d d,我们考虑 d = 0 d=0 d=0的时候怎么做。

我们要求 ∑ i = 0 n ( n i ) s n − i [ 4 ∣ i ] \sum_{i=0}^n{n\choose i}s^{n-i}[4\mid i] i=0n(in)sni[4i]

a i = ( n i ) s n − i a_i={n\choose i}s^{n-i} ai=(in)sni,注意这里翻转了一下,则我们由二项式定理知道: A ( x ) = ( x + s ) n A(x)=(x+s)^n A(x)=(x+s)n

于是

∑ i = 0 n ( n i ) s n − i [ 4 ∣ i ] = 1 4 ∑ i = 0 3 ( ω 4 i + s ) n \begin{aligned} \sum_{i=0}^n{n\choose i}s^{n-i}[4\mid i]&=&\frac{1}{4}\sum_{i=0}^{3}(\omega_4^i+s)^n \end{aligned} i=0n(in)sni[4i]=41i=03(ω4i+s)n

于是可以直接快速幂解决。

那么当 d d d不为 0 0 0的情况呢?

生成函数系数平移啊,也就是乘上若干个 x x x

于是乎,很愉快地,我们的答案出来了:

1 4 ∑ d = 0 3 a ( n + d ) % 4 ∑ i = 0 3 ( ω 4 i + s ) n ω 4 d i \frac{1}{4}\sum_{d=0}^3a_{(n+d)\%4}\sum_{i=0}^3(\omega_4^i+s)^n\omega_{4}^{di} 41d=03a(n+d)%4i=03(ω4i+s)nω4di

快速幂+递推就行了。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const 

cs int mod=998244353,inv4=748683265;
cs int w0=1,w1=911660635,w2=998244352,w3=86583718;
inline int add(int a,int b){return (a+=b)>=mod?a-mod:a;}
inline void Inc(int &a,int b){(a+=b)>=mod&&(a-=mod);}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline int power(int a,int b,int res=1){
	for(;b;b>>=1,a=mul(a,a))(b&1)&&(res=mul(res,a));
	return res;
}

ll n;
int nn,s,a[4],T;
int f0,f1,f2,f3,res;

signed main(){
	scanf("%d",&T);
	while(T--){
		scanf("%lld%d%d%d%d%d",&n,&s,&a[0],&a[1],&a[2],&a[3]);
		res=0,nn=n%(mod-1);
		f0=power(add(w0,s),nn);
		f1=power(add(w1,s),nn);
		f2=power(add(w2,s),nn);
		f3=power(add(w3,s),nn);
		Inc(res,mul(a[nn&3],add(add(f0,f1),add(f2,f3))));
		f1=mul(f1,w1);f2=mul(f2,w2);f3=mul(f3,w3);
		Inc(res,mul(a[nn+1&3],add(add(f0,f1),add(f2,f3))));
		f1=mul(f1,w1);f2=mul(f2,w2);f3=mul(f3,w3);
		Inc(res,mul(a[nn+2&3],add(add(f0,f1),add(f2,f3))));
		f1=mul(f1,w1);f2=mul(f2,w2);f3=mul(f3,w3);
		Inc(res,mul(a[nn+3&3],add(add(f0,f1),add(f2,f3))));
		std::cout<<mul(res,inv4)<<"\n";
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值