[AGC005D] ~K Perm Counting

[AGC005D] ~K Perm Counting

Description

给出 nk,求有多少个长度为 n 的排列 a 使得对于任意的 $ 1\leqslant i \leqslant n $ 都满足 ∣ai−i∣≠ k

数据范围:2⩽n⩽2000,1⩽k<n

Solution

显然容斥一波

剩下的回头补

 

#include<bits/stdc++.h>

using namespace std;

#define LL long long

inline LL read()
{
    LL f = 1 , x = 0;
    char ch;
    do
    {
        ch = getchar();
        if(ch=='-') f=-1;
    } while(ch<'0'||ch>'9');
    do
    {
        x=(x<<3) + (x<<1) + ch - '0';
        ch = getchar();
    }while(ch>='0'&&ch<='9');
    return f*x;
}

const int MAXN = 4000 + 10;
const int MOD = 924844033;

int n,k;
LL fac[MAXN];
LL dp[MAXN][MAXN][2],a[MAXN],tot;

int main()
{
    n = read(),k = read();
    fac[0] = fac[1] = 1;
    for(int i=2;i<=n;i++) fac[i] = (fac[i-1] * i) % MOD;
    for(int i=1;i<=k;i++)
    {
        for(int j=i;j<=n;j+=k) a[++tot] = j;
        for(int j=i;j<=n;j+=k) a[++tot] = j;
    }
    dp[1][0][0] = 1;
    for(int i=2;i<=(n<<1);i++)
    {
        for(int j=0;j<=min(n,i/2);j++)
        {
            dp[i][j][0] = (dp[i-1][j][0] + dp[i-1][j][1]) % MOD;
            if(j&&(a[i]-a[i-1]==k)) dp[i][j][1] = (dp[i-1][j-1][0]);
        }
    }
    LL ans = 0;
    for(int i=0;i<=n;i++)
    {
        if(!(i&1)) ans = (ans + fac[n-i] * (dp[n<<1][i][0] + dp[n<<1][i][1]) % MOD) % MOD;
        else ans = (ans - (fac[n-i] * (dp[n<<1][i][0] + dp[n<<1][i][1])%MOD) + MOD) % MOD;
    }
    cout << ans << endl;
}

 

posted @ 2020-11-13 21:41  wlzs1432  阅读(100)  评论(0编辑  收藏  举报