bzoj 3622 容斥+DP计数

题目&&题解:点击打开链接

题意:

给你两个序列 a,b  每个序列共 nn 个数 , 数之间两两不同

问 a 与 b   之间有多少配对方案 使得 ai>bi的对数 比 bi>ai的恰好多 k对.

(1kn2000)


代码写得是真的丑,这么简单的题还调了好久!

一定要把容斥的每一个细节推清楚再写,否则边界写错了挺难查出的!

下次这种简单的(无代码量)题10分钟要写完调完!


用rep来define for可以减少代码量,码风转换中。。。。

mod是1e9+9幸好也是质数,否则要n^2递推组合数


#include<bits/stdc++.h>
using namespace std;
#define maxn 2020
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define rep2(i,l,r) for(register int i = l ; i >= r ; i--)

typedef long long ll;
const ll mod = 1e9 + 9;
ll f[maxn][maxn],F[maxn],inv[maxn],fac[maxn],ans;
int a[maxn],b[maxn],n,k;

inline void Add(ll &x,ll y){
	x += y;
	if ( x >= mod ) x -= mod;
	else if( x < 0 ) x += mod;
}
ll power(ll x,int y){
	ll res = 1;
	while ( y ){
		if ( y & 1 ) res = res * x % mod;
		y >>= 1;
		x = x * x % mod;
	}
	return res;
}
void init(){
	inv[0] = fac[0] = 1;
	rep (i,1,n) fac[i] = fac[i - 1] * i % mod;
	inv[n] = power(fac[n],mod - 2);
	rep2(i,n - 1,1) inv[i] = inv[i + 1] * (i + 1) % mod;
/*	C[0][0] = 1;
	 rep (i, 1, n) {
        C[i][0] = 1;
        rep (j, 1, n)
            C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
    }*/
}
ll C(int n,int m){
	if ( !m || n == m ) return 1;
	return fac[n] * inv[m] % mod * inv[n - m] % mod;
}
int main(){
	//freopen("input.txt","r",stdin);
	scanf("%d %d",&n,&k);
//	if ( (n + k) % 2 ){ printf("0\n"); return 0; } 
	rep (i,1,n) scanf("%d",&a[i]);
	rep (i,1,n) scanf("%d",&b[i]);
	init();
	sort(a + 1,a + n + 1) , sort(b + 1,b + n + 1);
	f[0][0] = 1 , k = (n + k) / 2;
	rep (i,1,n){
		int num = upper_bound(b + 1,b + n + 1,a[i]) - b - 1;
		rep (j,0,num){
			Add(f[i][j],f[i - 1][j]);
			if ( j ) Add(f[i][j],f[i - 1][j - 1] * (num - j + 1) % mod);
		}
	}	
	/*rep (i,1,n){
		rep (j,0,n){
			cout<<f[i][j]<<" ";
		}
		cout<<endl;
	}*/
	rep (i,1,n) F[i] = f[n][i] * fac[n - i] % mod;
	rep (i,k,n){
		if ( (i - k) & 1 ) Add(ans,-C(i,k) * F[i] % mod);
		else Add(ans,C(i,k) * F[i] % mod);	
	}
	cout<<ans<<endl;
	return 0;
}


猜你喜欢

转载自blog.csdn.net/weixin_42484877/article/details/80959626