CSP-S模拟 10

T1 #1687. 二分图匹配 \(100pts\)

  • 正解:线段树优化DP即可,可以做到 \(O(n^2 \log n)\) ,赛时感觉这个比较显然就直接写了。
点击查看代码
#include <bits/stdc++.h>
const int N = 1e3 + 5;
const int M = 1e6 + 5;
using namespace std;
int n, m, ans;
string s1, s2;
vector<int> p[N];
bool vis[N];
int f[N], maxn[M << 2];
void update(int i, int l, int r, int x, int y)
{
    if (l == r)
    {
        maxn[i] = max(maxn[i], y);
        return;
    }
    int mid = (l + r) >> 1;
    if (x <= mid)
        update(i * 2, l, mid, x, y);
    else
        update(i * 2 + 1, mid + 1, r, x, y);
    maxn[i] = max(maxn[i * 2], maxn[i * 2 + 1]);
}
int query(int i, int l, int r, int x, int y)
{
    if (l >= x && r <= y)
        return maxn[i];
    int mid = (l + r) >> 1, ans = 0;
    if (x <= mid)
        ans = max(ans, query(i * 2, l, mid, x, y));
    if (y > mid)
        ans = max(ans, query(i * 2 + 1, mid + 1, r, x, y));
    return ans;
}
signed main()
{
    freopen("match.in", "r", stdin);
    freopen("match.out", "w", stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> m;
    cin >> s1 >> s2;
    s1 = ' ' + s1;
    s2 = ' ' + s2;
    for (int i = 1; i <= n; i++)
        s1[i] -= 'A' - 1;
    for (int i = 1; i <= m; i++)
        s2[i] -= 'A' - 1;
    for (int i = 1; i <= n; i++)
    {
        if (vis[s1[i]])
            continue;
        vis[s1[i]] = 1;
        for (int j = 1; j <= m; j++)
            if (s1[i] == s2[j])
                p[s1[i]].push_back(j);
    }
    for (int i = 1; i <= n; i++)
    {
        for (int k = p[s1[i]].size() - 1; k >= max(0, (int)p[s1[i]].size() - 10000); k--)
        {
            int j = p[s1[i]][k];
            if (j == 1)
            {
                f[i] = max(f[i], 1);
                continue;
            }
            int nw = query(1, 1, m, 1, j - 1) + 1;
            f[i] = max(f[i], nw);
            update(1, 1, m, j, nw);
        }
    }
    for (int i = 1; i <= n; i++)
        ans = max(ans, f[i]);
    cout << ans;
}

T2 #1688. 虚图 \(30pts\)

  • 部分分(\(30pts\)):直接跑n遍 dij 。
点击查看代码
#include <bits/stdc++.h>
#define int long long
const int N = 2e5 + 5;
using namespace std;
int n, m, T, ans = 1e18;
int dis[N];
bool vis[N];
vector<pair<int, int>> e[N];
int s[N];
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
void dij(int s)
{
    memset(dis, 0x3f, sizeof(dis));
    memset(vis, 0, sizeof(vis));
    dis[s] = 0;
    q.push({dis[s], s});
    while (q.size())
    {
        int x = q.top().second;
        q.pop();
        if (vis[x])
            continue;
        vis[x] = 1;
        for (auto y : e[x])
        {
            int to = y.first, w = y.second;
            if (dis[to] > dis[x] + w)
            {
                dis[to] = dis[x] + w;
                q.push({dis[to], to});
            }
        }
    }
}
signed main()
{
    freopen("map.in", "r", stdin);
    freopen("map.out", "w", stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> m >> T;
    for (int i = 1; i <= m; i++)
    {
        int u, v, w;
        cin >> u >> v >> w;
        e[u].push_back({v, w});
        e[v].push_back({u, w});
    }
    for (int i = 1; i <= T; i++)
        cin >> s[i];
    for (int i = 1; i <= T; i++)
    {
        dij(s[i]);
        for (int j = 1; j <= T; j++)
        {
            if (i == j)
                continue;
            ans = min(ans, dis[s[j]]);
        }
    }
    cout << ans;
}
  • 正解:建立超级源点找出每个关键点的支配范围(在该范围内的点离该点最近),设答案为 \(dis(u,v)\) ,则存在分界边使得路径上所有边一侧归于 \(u\) 一侧归于 \(v\) ,枚举此关键边即可。
  • 乱搞:大力优化部分分做法,加入一系列剪枝,可以爆标。
点击查看代码
#include <bits/stdc++.h>
#define int long long
const int N = 2e5 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
using namespace std;
int n, m, T, ans = inf;
int dis[N];
bool ys[N];
queue<int> vi;
vector<pair<int, int>> e[N];
int s[N];
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
void dij(int s)
{
    //memset(dis, 0x3f, sizeof(dis));
    //memset(vis, 0, sizeof(vis));
    vi.push(s);
    dis[s] = 0;
    q.push({dis[s], s});
    while (q.size())
    {
        int x = q.top().second;
        q.pop();
        if (dis[x] >= ans)
            continue;
        if (x != s && ys[x])
        {
            ans = dis[x];
            continue;
        }
        for (auto y : e[x])
        {
            int to = y.first, w = y.second;
            if (dis[to] > dis[x] + w)
            {
                if (dis[to] == inf)
                    vi.push(to);
                dis[to] = dis[x] + w;
                if (dis[to] > ans)
                    continue;
                q.push({dis[to], to});
            }
        }
    }
    while (!vi.empty())
        dis[vi.front()] = inf, vi.pop();
}
signed main()
{
    freopen("map.in", "r", stdin);
    freopen("map.out", "w", stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> m >> T;
    for (int i = 1; i <= m; i++)
    {
        int u, v, w;
        cin >> u >> v >> w;
        e[u].push_back({v, w});
        e[v].push_back({u, w});
    }
    memset(dis, 0x3f, sizeof(dis));
    for (int i = 1; i <= T; i++)
        cin >> s[i], ys[s[i]] = 1;
    for (int i = 1; i < T; i++)
        dij(s[i]);
    cout << ans;
}

T3 #1689. 冒泡 \(18pts\)

  • 部分分:逆序对。
点击查看代码
#include <bits/stdc++.h>
#define lowbit(x) (x & -x)
const int N = 5e5 + 5;
using namespace std;
int T, L, R, ans;
string ll, rr;
int tot, a[N];
// void update(int x, int val)
// {
//     for (int i = x; i <= tot; i += lowbit(i))
//         t[i] += val;
// }
// int query(int x)
// {
//     int sum = 0;
//     for (int i = x; i >= 1; i -= lowbit(i))
//         sum += t[i];
//     return sum;
// }
void solve()
{
    //cerr << 999;
    for (int i = 1; i <= tot; i++)
    {
        for (int j = i + 1; j <= tot; j++)
            ans += (a[i] > a[j]);
    }
    // cerr << ans << '\n';
}
void work(int x)
{
    //cerr << x;
    tot = 0;
    while (x)
        a[++tot] = x % 10 + 1, x /= 10;
    reverse(a + 1, a + tot + 1);
    //for (int i = 1; i <= tot; i++)
    //    cerr << a[i] << ' ';
    //cerr << '\n';
    solve();
}
signed main()
{
    freopen("bubble.in", "r", stdin);
    freopen("bubble.out", "w", stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> T;
    while (T--)
    {
        ans = 0;
        L = 0;
        R = 0;
        cin >> ll >> rr;
        if (ll == rr)
        {
            tot = 0;
            for (auto i : ll)
                a[++tot] = (i - '0');
            solve();
            cout << ans << '\n';
            continue;
        }
        for (int i = ll.size() - 1; i >= 0; i--)
            L += (ll[i] - '0') * pow(10, ll.size() - i - 1);
        for (int i = rr.size() - 1; i >= 0; i--)
            R += (rr[i] - '0') * pow(10, rr.size() - i - 1);
        //cerr << L << R;
        for (int i = L; i <= R; i++)
            work(i);
        cout << ans << '\n';
    }
}
  • 正解:神秘数位 DP ,不会。粘题解了,虽然题解写的壱陀矢根本不知所云

T4 #1690. 亲戚 \(19pts\)

  • 部分分:特判输出 YES 。
  • 正解:啥玩意儿。

总结

  • 实际上写完 T2 部分分就摆了,没有尝试很显然的乱搞。
  • 后两个小时完全不知道自己在干什么,全是垃圾时间。
posted @ 2025-08-13 17:26  S_Keep_Kiding  阅读(53)  评论(4)    收藏  举报