考虑容斥,发现按照i%2k分类,不同的i互补影响。
首先计数f(i,j)表示同一类中,i个位置有j个不满足限制的方案数,这个显然可以在平方时间复杂度内搞出来。
然后维护出g(i,j)表示i类,n个位置j个不满足限制的方案数。这个注意到i是O(k)级别的,转移是O(n/k)级别的,所以复杂度是平方的。
然后随便选就是阶乘。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define lint long long
#define mod 924844033
#define N 2010
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
int f[2][N][N][2],g[N][N],s[2][N][N],fac[N];
inline int sol(lint x,int s) { return x%=mod,((s&1)?(x?mod-x:0):x); }
inline int getf(int n,int a,int f[N][N][2],int s[N][N])
{
f[1][1][0]=a,f[1][1][1]=1;
s[0][0]=1,s[1][0]=1,s[1][1]=1+a;
for(int i=2;i<=n;i++)
{
s[i][0]=1,f[i][0][0]=f[i][0][1]=0;
for(int j=1;j<=i;j++)
f[i][j][0]=(s[i-2][j-1]+f[i-1][j-1][0])%mod,
f[i][j][1]=s[i-1][j-1],
s[i][j]=(1ll*s[i-1][j]+f[i][j][0]+f[i][j][1])%mod;
}
return 0;
}
inline int getabl(int r,int n,int k,int &a,int &b,int &l)
{ return a=(r>k),l=(n-r)/(2*k)+1,b=((2*l-1)*k+r<=n); }
inline int F(int f[N][N][2],int s[N][N],int l,int b,int t)
{ if(b) return s[l][t];return (s[l-1][t]+f[l][t][0])%mod; }
int main()
{
int n,k,mxL,ans=0;scanf("%d%d",&n,&k),mxL=(n-1)/(2*k)+1;
getf(mxL,0,f[0],s[0]),getf(mxL,1,f[1],s[1]),g[0][0]=1;
rep(i,0,min(n,2*k)-1)
{
int a,b,l;getabl(i+1,n,k,a,b,l);
rep(j,0,n) if(g[i][j]) rep(t,0,min(n-j,l))
(g[i+1][j+t]+=1ll*g[i][j]*F(f[a],s[a],l,b,t)%mod)%=mod;
}
for(int i=fac[0]=1;i<=n;i++) fac[i]=(lint)fac[i-1]*i%mod;
for(int i=0;i<=n;i++) (ans+=sol(1ll*fac[n-i]*g[min(n,2*k)][i],i))%=mod;
return !printf("%d\n",ans);
}