#单位根反演,二项式定理#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;
}
posted @ 2021-07-06 07:31  lemondinosaur  阅读(49)  评论(0编辑  收藏  举报