1. 程式人生 > >【容斥原理】【DP】AGC004D ~K Perm Counting

【容斥原理】【DP】AGC004D ~K Perm Counting

分析:

比較簡單(板)的容斥題。

設枚舉出i個非法位置的方案數為fif_i 答案就是i=0in(1)ifi(ni)!\sum_{i=0}^{i\leq n}(-1)^if_i*(n-i)!

問題就在於如何求fif_i。顯然,可以把互相可能矛盾的位置分為一類,然後每一類搞一個n2n^2的DP求出來有k個矛盾的方案數。然後所有的一起求個揹包。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define SF scanf
#define
PF printf
#define MAXN 2010 #define MOD 924844033 using namespace std; typedef long long ll; ll dp[MAXN][MAXN][2]; void prepare(){ dp[0][0][0]=1; dp[0][0][1]=1; for(int i=1;i<=2000;i++) for(int j=0;j<=i;j++){ dp[i][j][0]=dp[i-1][j][1]; if(i>=1&&j>=1) dp[i][j][0]+=dp[i-1][j-1][0]
; dp[i][j][0]%=MOD; dp[i][j][1]=dp[i][j][0]; if(i>=1&&j>=1) dp[i][j][1]+=dp[i-1][j-1][1]; dp[i][j][1]%=MOD; } } int n,k; ll sum[MAXN],fac[MAXN]; int main(){ prepare(); SF("%d%d",&n,&k); sum[0]=1; for(int i=1;i<=k*2&&i<=n;i++){ int lenx=(n-
i)/(k*2)+1; int fir=i-k; int las=(lenx-1)*k*2+i+k; int kd; if(fir>=1&&las<=n) kd=1; else if(fir>=1||las<=n) kd=0; else{ kd=1; lenx--; } /*PF("%d:{%d %d (%d %d)}\n",i,lenx,kd,fir,las); for(int j=0;j<=lenx;j++){ PF("[%d %lld]\n",j,dp[lenx][j][kd]); }*/ for(int i=n;i>=0;i--) for(int j=1;j<=lenx&&i-j>=0;j++){ sum[i]+=sum[i-j]*dp[lenx][j][kd]; sum[i]%=MOD; } /*PF("now,sum:\n"); for(int i=1;i<=n;i++) PF("{%d %lld}\n",i,sum[i]); PF("-----------\n");*/ } fac[0]=1; for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%MOD; ll ans=0; for(int i=0;i<=n;i++){ if(i%2==0) ans=(ans+sum[i]*fac[n-i])%MOD; else ans=(ans-sum[i]*fac[n-i])%MOD; } PF("%lld",(ans+MOD)%MOD); }