P7154 [USACO20DEC] Sleeping Cows P 题解

P7154 [USACO20DEC] Sleeping Cows P 题解

\(s, t\) 升序排序。

容易发现每一个 \(t_i\) 可匹配的 \(s_j\) 对应了一个前缀。

考虑刻画极大匹配,一个匹配是极大的当且仅当最大的没有被匹配的 \(t\) 小于最小的没有被匹配的 \(s\)

证明:充分性显然,如果一个匹配不是极大的,那么 \(\exists i, j, t_i\ge s_j\),其中 \(t_i, s_j\) 未匹配,转化为逆否命题得证必要性。

我们按数值从小到大考虑每一个 \(t_i\)\(s_j\),将它们按升序排成一行,如果把 \(t_i\) 视作黑球,\(s_j\) 视作白球,那么问题转化为了:前面的白球可以选择和后面的某一个黑球匹配,且最小没有匹配的白球后面没有未匹配的黑球。

这个经典的黑白球匹配问题可以用如下 DP 解决:\(f_{i, j, 0/1}\) 表示前 \(i\) 个球,有 \(j\) 个白球需要和后面的黑球匹配,是否有没有匹配的白球,转移考虑当前是黑球白球,以及是否和某个球匹配了。

时间复杂度 \(O(n^2)\)

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <ctime>
#define int long long
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
typedef unsigned long long ull;
const int N = 6000 + 10, mod = 1e9 + 7;

int n, a[N], b[N], w[N], f[N][N][2], idx;
PII p[N];

signed main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> n;
    for(int i = 1; i <= n; i ++) cin >> a[i], p[++ idx] = {a[i], 0};
    for(int i = 1; i <= n; i ++) cin >> b[i], p[++ idx] = {b[i], 1};
    sort(p + 1, p + idx + 1);
    f[0][0][0] = 1;
    for(int i = 1; i <= idx; i ++) {
        for(int j = 0; j <= i; j ++) {
            for(int o = 0; o < 2; o ++) {
                if(f[i - 1][j][o]) {
                    int v = f[i - 1][j][o];
                    if(p[i].y) { // black
                        if(!o) f[i][j][o] = (f[i][j][o] + v) % mod;
                        if(j) f[i][j - 1][o] = (f[i][j - 1][o] + v * j) % mod;
                    }
                    else {
                        f[i][j][1] = (f[i][j][1] + v) % mod;
                        f[i][j + 1][o] = (f[i][j + 1][o] + v) % mod;
                    }
                }
            }
        }
    }
    cout << (f[idx][0][0] + f[idx][0][1]) % mod << '\n';
    return 0;
}
posted @ 2025-10-28 23:30  MoyouSayuki  阅读(7)  评论(0)    收藏  举报
:name :name