Description

【JZOJ6151】星际穿越

Solution

fif_i表示前iKiK列的答案,考虑容斥,枚举有多少段连续上升的段,则有:
fi=j=0i1(iKjK)r(1)ij1fjf_i=\sum_{j=0}^{i-1}\binom{iK}{jK}^r(-1)^{i-j-1}f_j
拆开组合数,移项得:
fi((iK)!)r=j=0i1fj((jK)!)r(1)ij1(((ij)k)!)r\dfrac{f_i}{((iK)!)^r}=\sum_{j=0}^{i-1}\dfrac{f_j}{((jK)!)^r}\cdot\dfrac{(-1)^{i-j-1}}{(((i-j)k)!)^r}
F(x)=i=0fi((iK)!)rG(x)=i=1(1)i1((iK)!)rF(x)=\sum_{i=0}^{\infin}\dfrac{f_i}{((iK)!)^r},G(x)=\sum_{i=1}^{\infin}\dfrac{(-1)^{i-1}}{((iK)!)^r}
F(x)=F(x)G(x)+1F(x)=F(x)G(x)+1,即F(x)=11G(x)F(x)=\dfrac{1}{1-G(x)}
多项式求逆。至于最后不足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);
}

相关文章: