20260530模拟赛总结

分数总结

题目 期望分数 实际分数 挂分分数
A - 音乐节拍器 100pts 100pts 0pts
B - 连续打卡 100pts 100pts 0pts
C - 抓取卡牌 100pts 55pts 45pts
D - 子树染色 100pts 100pts 0pts
E - 勇闯迷宫 I don't know 40pts I don't know
F - 足球训练 30pts 30pts 0pts

题目解析

C - 抓取卡牌

眼睛不知道干什么去了,\(0 \le X,a_i \le 2 \times 10^5\),注意,有 \(0\)

时间复杂度\(O(n\log n)\)

空间复杂度:\(O(n)\)

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define ull unsigned long long
#define db double
#define inf (1 << 30)
#define lnf (1LL << 60)
#define all(x) (x).begin(), (x).end()
typedef pair<int, int> PII;
constexpr int N = 2e5 + 7;
constexpr int P = 998244353;

int n, x, v[N], a[N];

struct Node {
    int val, limit, k;
    bool operator < (const Node &A) const {
        return val / k < A.val / A.k;
    }
};

priority_queue<Node> q;

int main() {
    scanf("%d%d", &n, &x);
    for (int i = 1; i <= n; i++) scanf("%d", &v[i]);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    for (int i = 1; i <= n; i++) {
        if (a[i])
            q.push({v[i], a[i], 1});
    }
    ll ans = 0;
    while (x--) {
        auto t = q.top();
        q.pop();
        ans += t.val / t.k;
        if (t.k + 1 > t.limit) continue;
        q.push({t.val, t.limit, t.k + 1});
    }
    printf("%lld\n", ans);
    return 0;
}

E - 勇闯迷宫

关于 SPFA,他死了。

首先 \(90pts\) 做法,用 Dijkstra 来做最短路。

但是会 TLE,我们发现只有 \(0\)\(1\),所以可以 01BFS。

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define ull unsigned long long
#define db double
#define inf (1 << 30)
#define lnf (1LL << 60)
#define all(x) (x).begin(), (x).end()
typedef pair<int, int> PII;
constexpr int N = 300 + 7, MAXP = 100 + 7;
constexpr int P = 998244353;
constexpr int dx[] = {-1, 0, 0, 1, 0};
constexpr int dy[] = {0, -1, 1, 0, 0};

struct Node {
    int x, y, p;
    bool use;
};

int n, m, p, col[N][N];
int sx, sy, ex, ey;
char s[N][N];

ll dis[N][N][MAXP][2];
bool vis[N][N][MAXP][2];

deque<Node> dq;

void bfs() {
    memset(dis, 0x3f, sizeof(dis));
    dis[sx][sy][0][0] = 0;
    dq.push_back({sx, sy, 0, false});
    while (!dq.empty()) {
        auto u = dq.front();
        dq.pop_front();
        if (vis[u.x][u.y][u.p][u.use]) continue;
        vis[u.x][u.y][u.p][u.use] = true;
        if (!u.use) {
            for (int l = 0; l < p; l++) {
                int np = l, cost = 1;
                if (dis[u.x][u.y][u.p][u.use] + cost < dis[u.x][u.y][np][true]) {
                    dis[u.x][u.y][np][true] = dis[u.x][u.y][u.p][u.use] + cost;
                    Node v = {u.x, u.y, np, true};
                    dq.push_back(v);
                }
            }
        }
        for (int i = 0; i < 5; i++) {
            int nx = u.x + dx[i];
            int ny = u.y + dy[i];
            if (nx < 1 || nx > n || ny < 1 || ny > m) continue;
            if (s[nx][ny] == '#') continue;
            int np = (u.p + 1) % p;
            int cost = ((col[nx][ny] == u.p) ? 0 : 1);
            if (dis[u.x][u.y][u.p][u.use] + cost < dis[nx][ny][np][u.use]) {
                dis[nx][ny][np][u.use] = dis[u.x][u.y][u.p][u.use] + cost;
                Node v = {nx, ny, np, u.use};
                if (cost == 0) dq.push_front(v);
                else dq.push_back(v);
            }
        }
    }
    ll minv = lnf;
    for (int i = 0; i < p; i++)
        for (int u = 0; u < 2; u++)
            minv = min(minv, dis[ex][ey][i][u]);
    printf("%lld\n", minv == lnf ? -1 : minv);
}

int main() {
    scanf("%d%d%d", &n, &m, &p);
    for (int i = 1; i <= n; i++) {
        scanf("%s", s[i] + 1);
        for (int j = 1; j <= m; j++) {
            if (s[i][j] == 'S') {
                sx = i, sy = j;
            }
            if (s[i][j] == 'T') {
                ex = i, ey = j;
            }
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            scanf("%d", &col[i][j]);
        }
    }
    bfs();
    return 0;
}

F - 足球训练

简述题意:给定 \(n\) 个数对 \((a,b)\),每次可以将一个数对变成 \((a+b,b)\),求最后 \(a\) 的乘积最大是多少。

\(30\) 分做法:可以简单 DP。

先不考虑太多,设式子为 \(a_1 \times a_2 \times C\)

\(C\) 为其他的乘积。

如果是加上 \(a_1\) 更好,式子就变成了 \((a_1+b_1)\times a_2 \times C > (a_2+b_2)\times a_1 \times C\)

\(C\) 就约掉了。

然后用我们小学二年级就学过的交叉相乘得到

\[\dfrac{a_1+b_1}{a_1} > \dfrac{a_2+b_2}{a_2} \]

然后转换成带分数得到

\[1 + \dfrac{b_1}{a_1} > 1 + \dfrac{b_2}{a_2} \]

然后就变成了

\[\dfrac{b_1}{a_1} > \dfrac{b_2}{a_2} \]

所以说,想让 \(\dfrac{b}{a}\) 尽可能大。

\(60\) 分做法:可以维护一个堆,让 \(\dfrac{b}{a}\) 尽可能大。

其实 \(\dfrac{b}{a}\)\(\dfrac{a}{b}\) 是等价的。

我们可以二分 \(\min(\dfrac{a}{b}​)\) 的最大值。

然后,就找到他们之间的差值,判断是否大于 \(m\) 就好了。

\(100\) 分做法:像刚刚说的二分,然后剩下的按照 \(60\) 分做法的做,可以证明,\(m\) 一定小于等于 \(n\),因为如果大于的话,一定不是最优解。

代码:

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define int long long
#define ull unsigned long long
#define db double
#define inf (1 << 30)
#define lnf (1LL << 60)
#define all(x) (x).begin(), (x).end()
typedef pair<int, int> PII;
constexpr int N = 100000 + 7, MAXN = 3000 + 7;
constexpr int P = 998244353;

int n, m, a[N], b[N];

bool check(double mid) {
    int res = 0;
    for (int i = 1; i <= n; i++) {
        double v = 1.0 * a[i] / b[i];
        int cur = max(0.0, ceil(mid - v));
        res += cur;
    }
    return res <= m;
}

struct Node {
    int x, y, id;
    bool operator < (const Node &A) const {
        int nx = A.x, ny = A.y;
        return nx * y < x * ny;
    }
};

signed main() {
    scanf("%lld%lld", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%lld%lld", &a[i], &b[i]);
    double L = 0, R = 1e14;
    for (int i = 1; i <= 100; i++) {
        double mid = (L + R) / 2;
        if (check(mid)) L = mid;
        else R = mid;
    }
    priority_queue<Node> q;
    __int128 ans = 1;
    for (int i = 1; i <= n; i++) {
        double v = 1.0 * a[i] / b[i];
        int cur = max(0.0, ceil(L - v));
        a[i] += 1LL * cur * b[i];
        q.push({a[i], b[i], i});
        m -= cur;
    }
    assert(m <= n);
    // printf("%lf %lf\n", L, R);
    while (m--) {
        auto u = q.top();
        q.pop();
        a[u.id] += u.y;
        q.push({a[u.id], u.y, u.id});
    }
    for (int i = 1; i <= n; i++) ans *= a[i], ans %= P;
    printf("%lld\n", (ll)ans);
    return 0;
}
posted @ 2026-06-01 10:33  AKCoder  阅读(7)  评论(0)    收藏  举报