【容斥原理】【DP】AGC004D ~K Perm Counting
阿新 • • 發佈:2018-12-11
分析:
比較簡單(板)的容斥題。
設枚舉出i個非法位置的方案數為 答案就是
問題就在於如何求。顯然,可以把互相可能矛盾的位置分為一類,然後每一類搞一個的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);
}