传送门
蒟蒻的第一道单位根反演,感觉还挺好用的
考虑对于每个复读机列出生成函数:
F
=
∑
i
≥
0
[
d
∣
i
]
x
i
i
!
F
=
∑
i
≥
0
x
i
i
!
∑
j
=
1
d
(
ω
d
i
)
j
d
F
=
1
d
∑
j
=
1
d
∑
i
≥
0
(
ω
d
j
x
)
i
F
=
1
d
∑
i
=
1
d
e
ω
d
i
x
A
n
s
=
F
k
=
1
d
k
(
∑
i
=
1
d
e
ω
d
i
x
)
k
\begin{aligned}F=&\sum_{i\ge0}[d|i]\frac{x^i}{i!}\\F=&\sum_{i\ge0}\frac{x^i}{i!}\frac{\sum_{j=1}^d(\omega_d^i)^j}{d}\\F=&\frac1d\sum_{j=1}^d\sum_{i\ge0}(\omega_d^jx)^i\\F=&\frac1d\sum_{i=1}^de^{\omega_d^ix}\\Ans=&F^k=\frac1{d^k}(\sum_{i=1}^de^{\omega_d^ix})^k\end{aligned}
F=F=F=F=Ans=i≥0∑[d∣i]i!xii≥0∑i!xid∑j=1d(ωdi)jd1j=1∑di≥0∑(ωdjx)id1i=1∑deωdixFk=dk1(i=1∑deωdix)k
我们发现这个
d
≤
3
d\le3
d≤3,那么暴力
d
d
d项式展开用组合数计算系数即可。
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int mod=19491001,w3=18827933;
typedef long long ll;
inline int add(int a,int b){return (a+=b)<mod?a:a-mod;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline void Add(int&a,int b){(a+=b)<mod?a:a-=mod;}
inline void Dec(int&a,int b){(a-=b)<0?a+=mod:a;}
inline void Mul(int&a,int b){a=(ll)a*b%mod;}
inline int ksm(int a,int p){int ret=1;for(;p;p>>=1,Mul(a,a))if(p&1)Mul(ret,a);return ret;}
const int N=5e6+5;
int n,k,d,fac[N],ifac[N];
inline void init_fac(){
fac[0]=ifac[0]=fac[1]=ifac[1]=1;
for(ri i=2;i<=k;++i)fac[i]=mul(fac[i-1],i),ifac[i]=mul(ifac[mod-mod/i*i],mod-mod/i);
for(ri i=2;i<=k;++i)Mul(ifac[i],ifac[i-1]);
}
inline int C(int n,int m){return(ll)fac[n]*ifac[m]%mod*ifac[n-m]%mod;}
int main(){
cin>>n>>k>>d;
if(n!=n/d*d)return puts("0"),0;
if(d==1)return cout<<ksm(k,n),0;
init_fac();
if(d==2){
int res=0;
for(ri i=0;i<=k;++i)Add(res,mul(C(k,i),ksm(dec(2*i,k),n)));
cout<<mul(res,ksm(ksm(2,mod-2),k));
return 0;
}
int a=1,b=w3,c=mul(b,b),res=0;
for(ri i=0,t=0;i<=k;++i,t=0){
for(ri j=0,up=k-i;j<=up;++j)Add(t,mul(C(k-i,j),ksm(add(mul(a,i),add(mul(b,j),mul(c,k-i-j))),n)));
Add(res,mul(t,C(k,i)));
}
cout<<mul(res,ksm(ksm(3,mod-2),k));
return 0;
}