Description
Solution
设表示前列的答案,考虑容斥,枚举有多少段连续上升的段,则有:
拆开组合数,移项得:
设
则,即
多项式求逆。至于最后不足K的一段暴力卷积即可。
Code
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;++i)
#define fd(i,j,k) for(int i=j;i>=k;--i)
using namespace std;
typedef long long ll;
const int N=1e6+10,mo=998244353;
int qpow(int x,int y){
int s=1;
for(;y;y>>=1,x=(ll)x*x%mo) if(y&1) s=(ll)s*x%mo;
return s;
}
int pl(int x,int y){
return x+y>=mo?x+y-mo:x+y;
}
void inc(int &x,int y){
x=x+y>=mo?x+y-mo:x+y;
}
int rev[N*4],fn;
void NTT(int *a,int sig){
fo(i,1,fn-1) if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int m=2;m<=fn;m<<=1){
int hf=m>>1,w0=qpow(3,(mo-1)/m);
if(sig<0) w0=qpow(w0,mo-2);
for(int i=0;i<fn;i+=m)
for(int j=i,w=1;j<i+hf;++j,w=(ll)w*w0%mo){
int u=a[j],v=(ll)a[j+hf]*w%mo;
a[j]=pl(u,v),a[j+hf]=pl(u,mo-v);
}
}
if(sig<0){
int nn=qpow(fn,mo-2);
fo(i,0,fn-1) a[i]=(ll)a[i]*nn%mo;
}
}
int c[N*4];
void inv(int ln,int *a,int *b){
if(ln==1){
b[0]=qpow(a[0],mo-2);
return;
}
inv((ln+1)>>1,a,b);
int cnt=0;
for(fn=1;fn<(ln<<1);fn<<=1) ++cnt;
fo(i,1,fn-1) rev[i]=rev[i>>1]>>1|(i&1)<<(cnt-1);
fo(i,0,ln-1) c[i]=a[i];
fo(i,ln,fn-1) c[i]=b[i]=0;
NTT(c,1),NTT(b,1);
fo(i,0,fn-1) b[i]=(2-(ll)c[i]*b[i]%mo+mo)%mo*b[i]%mo;
NTT(b,-1);
fo(i,ln,fn-1) b[i]=0;
}
int jc[N],ny[N];
int f[N*4],a[N],g[N];
int main()
{
freopen("interstellar.in","r",stdin);
freopen("interstellar.out","w",stdout);
int n,r,k,t;
scanf("%d %d %d",&n,&r,&k),t=n/k;
jc[0]=1;
fo(i,1,n) jc[i]=(ll)jc[i-1]*i%mo;
ny[n]=qpow(jc[n],mo-2);
fd(i,n,1) ny[i-1]=(ll)ny[i]*i%mo;
a[0]=1;
fo(i,1,t) a[i]=(mo-qpow(ny[i*k],r)*(i&1?1:-1))%mo,g[i]=mo-a[i];
inv(t+1,a,f);
int ans=0;
if(n%k){
fo(i,0,t){
ll w=(qpow(ny[n-i*k],r)*((t-i)&1?-1:1)+mo)%mo;
inc(ans,(ll)f[i]*w%mo);
}
}
else ans=f[t];
ans=(ll)ans*qpow(jc[n],r)%mo;
printf("%d",ans);
}