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; }
弱者就是会被欺负呀