1. 程式人生 > 其它 >Loj#6247-九個太陽【單位根反演】

Loj#6247-九個太陽【單位根反演】

正題

題目連結:https://loj.ac/p/6247


題目大意

給出\(n,k\)

\[\sum_{0\leq i\leq n,i|k}\binom{n}{i} \]

\(998244353\)取模

\(1\leq n\leq 10^{15},1\leq k\leq 2^{20},k=2^p(p\in N)\)


解題思路

隨便找的一題竟然是單位根反演,不過很基礎而且很裸。

首先單位根反演的式子\([i|k]=\frac{1}{k}\sum_{j=0}^{k-1}\omega_k^{i\times j}\)

然後帶到這題的式子就是

\[\sum_{i=0}^n\frac{1}{k}\sum_{j=0}^{k-1}\omega_k^{i\times j}\binom{n}{i} \]

然後把\(j\)

提出來

\[\frac{1}{k}\sum_{j=0}^{k-1}\sum_{i=0}^n(\omega_k^{i})^j\binom{n}{i} \]

然後二項式定理

\[\frac{1}{k}\sum_{j=0}^{k-1}(\omega_k^{i}+1)^n \]

額但是\(n\)很大直接用複數精度肯定會炸,但是\(998244353-1=2^{23}\times 7\times 17\)...又因為\(k=2^p\),其實就是類似於\(NTT\)的思路我們直接用原根\(\omega_k^1=g^{\frac{P-1}{k}}\)就好了。

時間複雜度\(O(k\log n)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll P=998244353;
ll n,k,ans;
ll power(ll x,ll b){
	ll ans=1;
	while(b){
		if(b&1)ans=ans*x%P;
		x=x*x%P;b>>=1;
	}
	return ans;
}
signed main()
{
	scanf("%lld%lld",&n,&k);
	ll g=power(3,(P-1)/k),z=1;
	for(ll i=0;i<k;i++,z=z*g%P)
		(ans+=power(z+1,n)%P)%=P;
	printf("%lld\n",ans*power(k,P-2)%P);
	return 0;
}