agc005D ~K Perm Counting

题意:有多少排列对于每个位置$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;
}

 

posted @ 2018-06-28 11:12  shixinyi  阅读(405)  评论(0编辑  收藏  举报