• [CF1342E] Placing Rooks


    [题目链接]

    http://codeforces.com/contest/1342/problem/E

    [题解]

    首先当 (K geq N) 时答案显然为 (0)

    一个观察是 : 要么每行都有车 , 要么每列都有。

    这两者是独立的 , 只需考虑一种最后将答案乘 (2) 即可。

    也就是要将 (N) 个棋子放入 ((N - K)) 个不同的列中。

    方案数为 ({N choose K} cdot (N - K)! cdot {N race K})

    可以通过容斥求斯特林数。

    时间复杂度 : (O(N))

    [代码]

    #include<bits/stdc++.h>
     
    using namespace std;
     
    typedef long long LL;
     
    #define rep(i , l , r) for (int i = (l); i < (r); ++i)
     
    const int MN = 2e5 + 5 , mod = 998244353;
     
    int fac[MN] , ifac[MN] , pw[MN] , pr[MN] , N , K;
     
    inline void inc(int &x , int y) {
    	x = x + y < mod ? x + y : x + y - mod;
    }
    inline void dec(int &x , int y) {
    	x = x - y >= 0 ? x - y : x - y + mod;
    }
    inline int qPow(int a , int b) {
    	int c = 1;
    	for (; b; b >>= 1 , a = 1ll * a * a % mod) if (b & 1) c = 1ll * c * a % mod;
    	return c;
    }
    inline void init(int n) {
    	fac[0] = 1;
    	for (int i = 1; i <= n; ++i) fac[i] = 1ll * fac[i - 1] * i % mod;
    	ifac[n] = qPow(fac[n] , mod - 2);
    	for (int i = n - 1; i >= 0; --i) ifac[i] = 1ll * ifac[i + 1] * (i + 1) % mod;
    	return;
    }
    inline void sieve(int n , int k) {
    	int cnt = 0;
    	pw[1] = 1;
    	for (int i = 2; i <= n; ++i) {
    		if (!pw[i]) {
    			pr[++cnt] = i;
    			pw[i] = qPow(i , k);
    		}
    		for (int j = 1; j <= cnt && i * pr[j] <= n; ++j) {
    			pw[i * pr[j]] = 1ll * pw[i] * pw[pr[j]] % mod;
    			if (i % pr[j] == 0) break;
    		}
    	}
    }
    inline int S(int n , int m) {
    	sieve(m , n);
    	int res = 0;
    	for (int i = 1; i <= m; ++i) {
    		int val = 1ll * pw[i] * ifac[i] % mod * ifac[m - i] % mod;
    		if ((m - i) & 1) dec(res , val); else inc(res , val);
    	}
    	return res;
    }
     
    int main() {
    	 LL _K;
    	 scanf("%d%lld" , &N , &_K);
    	 if (_K >= N) {
    	 	 printf("0
    ");
    	 	 return 0;
    	 }
    	 K = _K;
    	 init(N - K);
    	 if (K == 0) {
    	 	printf("%d
    " , fac[N]);
    	 	return 0;
    	 }
    	 int ans = 2LL * S(N , N - K) % mod;
    	 for (int i = N; i > K; --i) ans = 1LL * ans * i % mod;
    	 printf("%d
    " , ans);
         return 0;
    }
    
  • 相关阅读:
    线性单链表动态内存分配(C语言实现)
    线性顺序表动态内存分配(C语言实现)
    Linux-v01天-课堂笔记
    博客园之自定义博客(美化+播放器)
    递归练习
    算法基础练习-_06 二进制小数
    算法基础练习-_05将整数的奇偶位互换
    算法基础练习-_03 1的个数
    算法基础练习-_01找出唯一成对的数
    常用算法之快速排序
  • 原文地址:https://www.cnblogs.com/evenbao/p/14441309.html
Copyright © 2020-2023  润新知