• BZOJ3622 已经没有什么好害怕的了 二项式反演+DP


    题目传送门

    https://lydsy.com/JudgeOnline/problem.php?id=3622

    题解

    首先显然如果 (n - k) 为奇数那么就是无解。否则的话,“糖果”比“药片”大的组数,应该为 (frac {n+k}2)

    考虑到多恰好 (k) 组不太好求,但是如果选了 (k) 组必须是“糖果”比“药片”大,这个方案数还是很好求的。

    首先是选了 (k) 组必须是“糖果”比“药片”大的方案数,这可以用一个 dp 解决。我们将糖果排序,然后预处理 (s_i) 表示有 (s_i) 个药片比糖果小。设 (dp[i][j]) 表示前 (i) 个糖果选了 (j) 个糖果比药片大的组合。转移的时候枚举当前这一个选不选就可以了。

    [dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1] cdot(s_i - j + 1) ]

    然后我们令 (f(k)) 表示钦定了 (i) 对“糖果”比“药片”大以后的方案数。那么显然有

    [f(k)=dp[n][k]cdot(n-k)! ]

    同时可以发现,如果令 (g(k)) 为恰好 (i) 对“糖果”比“药片”大的方案数,那么有

    [f(k)=sum_{i=k}^n inom ik g(i) ]

    所以直接二项式反演就可以了。


    代码如下,时间复杂度 (O(n^2))

    #include<bits/stdc++.h>
    
    #define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
    #define dbg(...) fprintf(stderr, __VA_ARGS__)
    #define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    #define fi first
    #define se second
    #define pb push_back
    
    template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
    template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}
    
    typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
    
    template<typename I>
    inline void read(I &x) {
    	int f = 0, c;
    	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    	x = c & 15;
    	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    	f ? x = -x : 0;
    }
    
    const int N = 2000 + 7;
    const int P = 1e9 + 9;
    
    int n, k;
    int a[N], b[N], s[N], dp[N][N], f[N];
    
    inline int smod(int x) { return x >= P ? x - P : x; }
    inline void sadd(int &x, const int &y) { x += y; x >= P ? x -= P : x; }
    inline int fpow(int x, int y) {
    	int ans = 1;
    	for (; y; y >>= 1, x = (ll)x * x % P) if (y & 1) ans = (ll)ans * x % P;
    	return ans;
    }
    
    int fac[N], inv[N], ifac[N];
    inline void ycl(const int &n = ::n) {
    	fac[0] = 1; for (int i = 1; i <= n; ++i) fac[i] = (ll)fac[i - 1] * i % P;
    	inv[1] = 1; for (int i = 2; i <= n; ++i) inv[i] = (ll)(P - P / i) * inv[P % i] % P;
    	ifac[0] = 1; for (int i = 1; i <= n; ++i) ifac[i] = (ll)ifac[i - 1] * inv[i] % P;
    }
    inline int C(int x, int y) {
    	if (x < y) return 0;
    	return (ll)fac[x] * ifac[y] % P * ifac[x - y] % P;
    }
    
    inline void work() {
    	if ((n - k) & 1) {
    		puts("-1");
    		return;
    	} else k = (n + k) / 2;
    	
    	std::sort(a + 1, a + n + 1);
    	for (int i = 1; i <= n; ++i)
    		for (int j = 1; j <= n; ++j) if (b[j] < a[i]) ++s[i];
    	dp[0][0] = 1;
    	for (int i = 1; i <= n; ++i)
    		for (int j = 0; j <= i; ++j) {
    			dp[i][j] = dp[i - 1][j];
    			if (j) sadd(dp[i][j], (ll)dp[i - 1][j - 1] * (s[i] - j + 1) % P);
    		}
    		
    	ycl();
    	for (int i = 0; i <= n; ++i) f[i] = (ll)dp[n][i] * fac[n - i] % P;
    	int ans = 0;
    	for (int i = k; i <= n; ++i)
    		if ((i - k) & 1) sadd(ans, P - (ll)C(i, k) * f[i] % P);
    		else sadd(ans, (ll)C(i, k) * f[i] % P);
    	printf("%d
    ", ans);
    }
    
    inline void init() {
    	read(n), read(k);
    	for (int i = 1; i <= n; ++i) read(a[i]);
    	for (int i = 1; i <= n; ++i) read(b[i]);
    }
    
    int main() {
    #ifdef hzhkk
    	freopen("hkk.in", "r", stdin);
    #endif
    	init();
    	work();
    	fclose(stdin), fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    oracle 同义词
    Git分支操作
    [转]Hibernate状态 (merge,attachDirty,attachClean)
    [转]对jQuery的事件绑定的一些思考
    [转]为什么用Spring来管理Hibernate?
    [转]spring注入静态bean
    ajax 请求调用问题
    Java常用开发组件介绍
    Spring @Value SpEl 知识点小记
    radio中最佳解决方案
  • 原文地址:https://www.cnblogs.com/hankeke/p/BZOJ3622.html
Copyright © 2020-2023  润新知