zoukankan      html  css  js  c++  java
  • [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
    ", ans);
    }
    

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

  • 相关阅读:
    内部类
    this关键字
    封装
    构造方法
    类图
    StringBuffer
    String
    导包
    包名规范
    带参数的方法
  • 原文地址:https://www.cnblogs.com/lizehon/p/11211599.html
Copyright © 2011-2022 走看看