LOJ6247 九个太阳
题目传送门
分析:
给出\(N\)和\(K\),求:
\[\sum_{i=0}^{n}[k|i]\binom{n}{i}
\]
想一下\([k|i]\)怎么表达
开始离谱的构造
找到\(k\)次单位根\(w_k=g^{\frac{p-1}{k}}\)
发现:
\[\sum_{j=0}^{k-1}w_k^{ij}=[k|i]k
\]
当\(k|i\)时,\(w_k^i=1\),显然成立
否则等比数列求和,\(\sum_{j=0}^{k-1}w_k^{ij}=\frac{1-w_k^{ik}}{1-w_k^i}=0\),也成立
好离谱的构造2333
开始推式子:
\[\sum_{i=0}^{n}[k|i]\binom{n}{i}
\]
\[=\sum_{i=0}^{n}\frac{1}{k}\sum_{j=0}^{k-1}w_k^{ij}\binom{n}{i}
\]
\[=\frac{1}{k}\sum_{j=0}^{k-1}\sum_{i=0}^{n}w_k^{ij}\binom{n}{i}
\]
\[=\frac{1}{k}\sum_{j=0}^{k-1}(w_k^j+1)^n
\]
(二项式定理)
直接算,复杂度\(O(klogn)\)
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define maxn 2000005
#define MOD 998244353
using namespace std;
inline long long getint()
{
long long num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
int n,k;
inline int ksm(int num,int k)
{
int ret=1;
for(;k;k>>=1,num=1ll*num*num%MOD)if(k&1)ret=1ll*ret*num%MOD;
return ret;
}
int main()
{
n=getint()%(MOD-1),k=getint();
int ans=0;
int wn=ksm(3,(MOD-1)/k),w=ksm(3,(MOD-1)/k);
for(int i=0;i<k;i++)
{
(ans+=ksm(w+1,n))%=MOD;
w=1ll*w*wn%MOD;
}
ans=1ll*ans*ksm(k,MOD-2)%MOD;
printf("%d\n",ans);
}