[AT2062] ~K Perm Counting

AT2602 , Luogu

求对于 \(n\) 个数的排列 , 有多少种方案满足对于所有的 \(i\) , \(|P_i - i| != K\) , 答案对 \(924844033\) 取模 .
\(n,K \le 2000\)

\(g[i]\) 表示至少有 \(i\) 个数不满足题意的方案数 , 则 \(ans = \sum_{i=0}^n (-1)^{i} g[i]\) .
可以画一个二分图 , 左边表示下标 , 右边表示取值 , 相隔 \(K\) 格的左右连一条边 . 网上有一个图 :

对于每一条链 , 每个点只能连一条边 . 所以在每一条链上有转移 : 设 \(f[i][j][0/1]\) 表示选到第 \(i\) 个数 , 已经连了 \(j\) 条边 , \(i\)\(i-1\) 是否连边的方案数 , 在链的内部转移 .
对于所有的链 , 可以拼接在一起 , 链之间也可以转移 \(f[i][j][0]\) 的方案数 , 这就相当于继承之前的结果继续 \(DP\) .

要特别注意的是 , 拼接的链的长度是 \(2n\) .
时间复杂度 \(O((2n)^2)\)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cassert>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define Debug(x) cout<<#x<<"="<<x<<endl
using namespace std;
typedef long long LL;
const int INF=1e9+7;
inline LL read(){
    register LL x=0,f=1;register char c=getchar();
    while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
    while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
    return f*x;
}

const int N = 4005;
const int mod = 924844033;

int a[N], g[N], f[N][N][2], fac[N];
int n, K, cnt, ans;

inline int add(int x, int y){return (x+y)%mod;}
inline int dec(int x, int y){return (x-y+mod)%mod;}
inline int mul(LL x, int y){return x*y%mod;}

int main(){
    n = read(), K = read();
    fac[0] = fac[1] = 1;
    for(int i = 2; i <= n; ++i) fac[i] = mul(fac[i-1], i);
    for(int i = 1; i <= K; ++i){
        for(int j = i; j <= n; j += K)
            a[++cnt] = j;
        for(int j = i; j <= n; j += K)
            a[++cnt] = j;
    }
    assert(cnt == (n << 1));
    f[1][0][0] = 1;
    for(int i = 2; i <= (n << 1); ++i){
        for(int j = 0; j <= min(n, i/2); ++j){
            f[i][j][0] = add(f[i-1][j][0], f[i-1][j][1]);
            if(j > 0 && a[i] - a[i-1] == K) f[i][j][1] = f[i-1][j-1][0];
        }
    }
    for(int i = 0; i <= n; ++i){
        g[i] = add(f[n << 1][i][0], f[n << 1][i][1]);
        if(!(i&1)) ans = add(ans, mul(g[i], fac[n - i]));
        else ans = dec(ans, mul(g[i], fac[n - i]));
    }
    printf("%d\n", ans);
}

\(CF\) 上还有一篇讨论 , 是这题的 \(NTT\) 做法 : Solve AGC005D with NTT

猜你喜欢

转载自www.cnblogs.com/lizehon/p/11211599.html