NaCly_Fish
2020-05-30 23:17:46
djq 提到了一种时间复杂度更优的解法,看到洛谷题解区还没有,就来复读一遍吧(
省略亿点步骤,题目中要求的可以转化为如下问题:
其中
由于 EGF 不太好搞,而关于
这样要求的就是
然后答案就能写成
只要求出
具体来讲,答案可以写为
线性筛求幂,是
然后使用万能的(并不)求导大法,就能推出:
设
要算
的系数就好了。
显然可以
总时间复杂度
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 100003
#define ll long long
#define reg register
#define p 998244353
using namespace std;
inline int add(const int& x,const int& y){ return x+y>=p?x+y-p:x+y; }
inline int power(int a,int t){
int res = 1;
while(t){
if(t&1) res = (ll)res*a%p;
a = (ll)a*a%p;
t >>= 1;
}
return res;
}
int inv[N],pw[N],pr[N>>2],fac[N],ifac[N];
void sieve(int n,int k){
int cnt = 0;
fac[0] = fac[1] = ifac[0] = ifac[1] = inv[1] = pw[1] = 1;
for(reg int i=2;i<=n;++i){
inv[i] = (ll)(p-p/i)*inv[p%i]%p;
fac[i] = (ll)fac[i-1]*i%p;
if(!pw[i]){
pr[++cnt] = i;
pw[i] = power(i,k);
}
for(reg int j=1;j<=cnt&&i*pr[j]<=n;++j){
pw[i*pr[j]] = (ll)pw[i]*pw[pr[j]]%p;
if(i%pr[j]==0) break;
}
}
ifac[n] = power(fac[n],p-2);
for(reg int i=n-1;i;--i) ifac[i] = (ll)ifac[i+1]*(i+1)%p;
}
inline int binom(int n,int m){ return (ll)fac[n]*ifac[m]%p*ifac[n-m]%p; }
int d,n,k,ans,sgn,a,b,bm;
int g[N],q[N];
int main(){
scanf("%d%d%d",&d,&n,&k);
if((k<<1)<=n-d){
printf("%d",power(d,n));
return 0;
}else if((k<<1)>n){
putchar('0');
return 0;
}
k = min(d,n-(k<<1));
sgn = n&1?-1:1;
sieve(d+1,n);
bm = (ll)d*binom(d-1,k)%p;
a = d-k-1,b = k;
q[0] = b&1?-1:1,q[1] = (b&1?-1:1)*a+((b-1)&1?-b:b);
for(reg int i=1;i!=d;++i) q[i+1] = -((ll)a*(q[i-1]-q[i])%p+(ll)b*(q[i-1]+q[i])-(ll)(i-1)*q[i-1])%p*inv[i+1]%p;
for(reg int i=0;i!=d;++i) g[i] = (ll)q[i]*bm%p*inv[d-i]%p;
for(reg int i=0;i<=k;++i) g[d] = add(g[d],binom(d,i));
for(reg int i=0;i<=d;++i){
if((i<<1)<d) ans = (ans+(ll)g[i]*sgn*pw[d-(i<<1)])%p;
else ans = (ans+(ll)g[i]*pw[(i<<1)-d])%p;
}
ans = (ll)ans*power(2,p-1-d)%p;
printf("%d",ans<0?ans+p:ans);
return 0;
}