题意:有多少排列对于每个位置$i$都满足$|a_i-i| \ne k$
$k < n \leq 2000$
一道简单的容斥+dp。事实证明,我做题思考的时候要靠感觉不能靠兴趣。
一开始就感觉应该是每个同余类分别dp,然后再合起来就可以了。
求出有i个位置是不合法的值,其他位置不确定,的方案数。最后容斥。
但是后来总是想把这道题往图论上面靠,就把NicoDafaGood带偏了。
dp写得比较拙劣
//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
#define ll long long
#define db double
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
const int maxn=2000+7;
const ll mod=924844033;
ll n,K,sum[maxn],mi[maxn],ans;
ll f[2][maxn][maxn][4],dp[maxn][maxn];
template<typename T>void read(T& aa) {
aa=0;char cc=getchar();T ff=1;
while((cc!='-')&&(cc<'0'||cc>'9')) cc=getchar();
if(cc=='-') ff=-1,cc=getchar();
while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
aa*=ff;
}
void get_dp(int n,int o) {
f[o][0][0][1]=1;
For(i,0,n-1) For(j,0,i) For(k,0,3) {
if(!f[o][i][j][k]) continue;
f[o][i][j][k]%=mod;
f[o][i+1][j][k>>1]+=f[o][i][j][k];
if((k&1)==0) f[o][i+1][j+1][k>>1]+=f[o][i][j][k];
if(i!=n-1) f[o][i+1][j+1][(k>>1)+2]+=f[o][i][j][k];
}
For(i,0,n) {
For(j,1,3) f[o][n][i][0]+=f[o][n][i][j];
f[o][n][i][0]%=mod;
}
}
int main() {
read(n); read(K); int x,y;
mi[0]=1; For(i,1,n) mi[i]=mi[i-1]*(ll)i%mod;
For(i,1,K) sum[i]=(n-i)/K+1;
get_dp(sum[K],0);
if(sum[1]>sum[K]) get_dp(sum[1],1);
dp[0][0]=1;
For(i,1,K) {
For(j,0,sum[i-1]) if(dp[i-1][j]) {
x=sum[i]; y=x-sum[K];
For(k,0,x) dp[i][j+k]+=dp[i-1][j]*f[y][x][k][0]%mod;
}
sum[i]+=sum[i-1];
For(j,0,sum[i]) dp[i][j]%=mod;
}
For(i,0,n) dp[K][i]=dp[K][i]*mi[n-i]%mod;
For(i,0,n) {
if(i&1) ans+=mod-dp[K][i];
else ans+=dp[K][i];
}
printf("%lld\n",ans%mod);
return 0;
}