1. 程式人生 > 實用技巧 >[AGC005D] ~K Perm Counting

[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; }