https://www.lydsy.com/JudgeOnline/problem.php?id=3622
XJOI题 不过没做过。。
容斥计数啊
先排序
记\(f[i][j]\)为前\(i\)位有\(j\)位固定且\(a[j] > b[k]\)的方案数
\[f[i][j] = f[i - 1][j] + f[i - 1][j - 1] \times (last - (j - 1))\]
\(last\)为最大的\(k\)使得\(a[i] > b[k]\)
有
\[f[n][i] = \sum_{k=i}^{n}ans[k] \binom{k}{i}\]
这部分是容斥
然后\(\mathcal O(n ^ 2)\)暴力维护就好了
感觉好套路
#include <bits/stdc++.h>
#define int long long
#define rint register int
#define fo(i, n) for(rint i = 1; i <= (n); i ++)
#define out(x) cerr << #x << " = " << x << "\n"
#define type(x) __typeof((x).begin())
#define foreach(it, x) for(type(x) it = (x).begin(); it != (x).end(); ++ it)
using namespace std;
// by piano
template<typename tp> inline void read(tp &x) {
x = 0;char c = getchar(); bool f = 0;
for(; c < '0' || c > '9'; f |= (c == '-'), c = getchar());
for(; c >= '0' && c <= '9'; x = (x << 3) + (x << 1) + c - '0', c = getchar());
if(f) x = -x;
}
const int mo = 1e9 + 9;
const int N = 2333;
int n, K;
int c[N][N], fac[N], f[N][N], ans[N], nxt[N], a[N], b[N];
main(void) {
read(n); read(K);
if((n - K) & 1) return puts("0"), 0;
K = n - (n - K) / 2;
for(int i = 0; i <= n; i ++)
c[i][0] = 1;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++)
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mo;
fac[0] = 1;
for(int i = 1; i <= n; i ++)
fac[i] = fac[i - 1] * i % mo;
for(int i = 1; i <= n; i ++) read(a[i]);
for(int i = 1; i <= n; i ++) read(b[i]);
sort(a + 1, a + n + 1); sort(b + 1, b + n + 1);
for(int i = 1; i <= n; i ++) {
for(int k = 1; k <= n; k ++)
if(a[i] > b[k])
nxt[i] = k;
}
f[0][0] = 1;
for(int i = 1; i <= n; i ++) {
for(int j = 0; j <= n; j ++) {
f[i][j] = f[i - 1][j];
if(j && nxt[i] - (j - 1) > 0) f[i][j] = (f[i][j] + f[i - 1][j - 1] * (nxt[i] - (j - 1)) % mo) % mo;
}
}
for(int j = 0; j <= n; j ++)
ans[j] = f[n][j] * fac[n - j] % mo;
for(int j = n - 1; j >= 0; j --) {
for(int i = j + 1; i <= n; i ++)
ans[j] = (ans[j] - ans[i] * c[i][j] % mo + mo) % mo;
}
cout << ans[K] << "\n";
}
原文地址:https://www.cnblogs.com/foreverpiano/p/9276839.html
时间: 2024-10-11 13:17:42