1. 程式人生 > 其它 >#單位根反演,二項式定理#LOJ 6247 九個太陽

#單位根反演,二項式定理#LOJ 6247 九個太陽

題目

\[\large {\sum_{i=0}^n[k|i]C(n,i)}\pmod {998244353} \]

其中\(n\leq 10^{18}\),\(k=2^p,p\in [0,20]\)


分析

主要是\(k\)條件比較難想,但是貌似有點像NTT的原根,
而且這個組合數也難求,二項式定理是一個將組合數轉換為一個快速冪的定理
主要是沒寫過單位根反演,直接推式子算了
單位根有一個很重要的性質就是

\[\large[n|k]=\frac{1}{n}\sum_{i=0}^{n-1}\omega^{ik}_n \]

然後這個式子就可以寫成

\[\large=\frac{1}{k}\sum_{i=0}^n\sum_{j=0}^{k-1}\omega^{ij}_kC(n,i) \]

考慮把有關\(i\)

的部分丟進裡面,那就是

\[\large=\frac{1}{k}\sum_{j=0}^{k-1}\sum_{i=0}^n(\omega^j_k)^{i}C(n,i) \]

觀察到後面直接套用二項式定理就是

\[\large=\frac{1}{k}\sum_{j=0}^{k-1}(\omega^j_k+1)^n \]

直接\(O(klog_2n)\)求就可以了


程式碼

#include <cstdio>
#define rr register
using namespace std;
typedef long long lll;
const lll mod=998244353;
lll n,k,omega,ans;
inline lll ksm(lll x,lll y){
	rr lll ans=1;
	for (;y;y>>=1,x=x*x%mod)
	    if (y&1) ans=ans*x%mod;
    return ans;
}
signed main(){
	scanf("%lld%lld",&n,&k);
	omega=ksm(3,(mod-1)/k);
	for (rr lll i=0,t=1;i<k;++i)
		ans+=ksm(t+1,n),t=t*omega%mod;
	return !printf("%lld",ans%mod*ksm(k,mod-2)%mod);
}