[luogu P4859] 已经没有什么好害怕的了
我丢 : https://www.luogu.com.cn/problem/P4859
思路
这题的关键在
保证上面两行不会有重复的数字。
这句话
也就是说不存在相等的情况
那么问题转化为一一配对,使得恰好
(
n
+
k
)
/
2
(n+k)/2
(n+k)/2对
a
i
>
b
i
a_i>b_i
ai>bi
题解
恰好的不是很好求
但很明显钦定的很好求
所以可以直接用二项式反演
对于钦定的可以DP求出来
先把
a
,
b
a,b
a,b从小到大排序
设
f
[
i
]
[
j
]
表
示
前
i
个
,
有
j
个
a
>
b
的
情
况
,
c
n
t
[
i
]
表
示
有
c
n
t
[
i
]
个
b
小
于
a
[
i
]
设f[i][j]表示前i个,有j个a > b的情况,cnt[i]表示有cnt[i]个b小于a[i]
设f[i][j]表示前i个,有j个a>b的情况,cnt[i]表示有cnt[i]个b小于a[i]
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
−
1
]
∗
(
c
n
t
[
i
]
−
(
j
−
1
)
)
f[i][j]=f[i-1][j-1]*(cnt[i]-(j-1))
f[i][j]=f[i−1][j−1]∗(cnt[i]−(j−1))
求完之后把剩下的随意配对
f
[
n
]
[
i
]
=
f
[
n
]
[
i
]
∗
(
n
−
i
)
!
f[n][i]=f[n][i]*(n-i)~!
f[n][i]=f[n][i]∗(n−i) !
然后二项式反演求出恰好的即可
code:
#include<bits/stdc++.h>
#define mod 1000000009
#define int long long
#define N 2005
using namespace std;
int a[N], b[N], c[N][N], cnt[N], f[N], fac[N], n, k;
signed main() {
scanf("%lld%lld", &n, &k);
fac[0] = 1;
for(int i = 1; i <= n; i ++) fac[i] = fac[i - 1] * i % mod;
for(int i = 0; i <= n; i ++) c[i][0] = 1;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= i; j ++)
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
int m = (n + k) / 2;
for(int i = 1; i <= n; i ++) scanf("%lld", &a[i]);
for(int i = 1; i <= n; i ++) scanf("%lld", &b[i]);
sort(a + 1, a + 1 + n), sort(b + 1, b + 1 + n);
b[n + 1] = 2147483647;
for(int i = 1; i <= n; i ++) cnt[i] = lower_bound(b + 1, b + 1 + n + 1, a[i]) - b - 1;
f[0] = 1;
for(int i = 1; i <= n; i ++)
for(int j = n; j >= 1; j --)
f[j] += f[j - 1] * max(cnt[i] - (j - 1), 0ll) % mod, f[j] %= mod;
int ans = 0;
for(int i = m; i <= n; i ++)
ans = (ans + ((i - m & 1)? -1 : 1) * c[i][m] % mod * f[i] % mod * fac[n - i] % mod + mod) % mod;
printf("%lld", ans);
return 0;
}