CSP-J 2023 题解

小苹果

链接:https://www.luogu.com.cn/problem/P9748

思路

第一问比较简单。我们发现,每天拿走的苹果的总数除 $3$ 向上取整,换种说法:定义 $m$ 为目前的总数,那么每天取走的就是 $\lfloor\frac{m}{3}\rfloor$。

在看第二问的时候,我们发现了题目问的恰好是第 $n$ 个苹果什么时候取走,那么我们按上面的方式,当 $m \bmod 3 = 1$,那么苹果就是那一轮拿走的。

代码

#include <bits/stdc++.h>
using namespace std;
long long a[10005] = {1}, n, I, tt, II;
int main() {
    cin >> n;
    for (int i = 1; i <= 33; i ++) a[i] = a[i - 1] * 3;
    int nn = n;
    while (n) {
        long long t = (n + 2) / 3;
        n -= t;
        I ++;//计数器

    }
    while (nn) {
        long long t = (nn + 2) / 3;
        if (nn % 3 == 1) {
            tt = II;
            //发现答案
            break;
        }
        nn -= t;
        II ++;
        // if (nn % 3 == 1) {
        //     tt = II;
        //     break;
        // }
    }
    cout << I << " " << tt + 1;
    return 0;
}

公路

赤裸裸的贪心。

贪心思路:每次把油加到够到达下一个油费最小的,注意最后一个加油站的邮费为 -inf

注意每次到达下一次加油时有可能有剩余的。

#include <bits/stdc++.h>
using namespace std;
long long n, m, v[100005], a[100005], s[100005], V;
int main() {
    // freopen("road.in", "r", stdin);
    // freopen("road.out", "w", stdout);
    cin >> n >> m;
    for (int i = 1; i < n; i ++) {
        cin >> v[i];
    }

    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
    }
    for (int i = 2; i <= n; i ++) {
        s[i] = s[i - 1] + v[i - 1];
        // cout << s[i] << "\n1\n";
    }
    // cout << "1";
    a[n] = 0;
    // cout << 1;
    long long ans = 0;
    for (int i = 1; i <= n;) {
        if (i == n) break;//注意终点站不用加油
        int minn = n;
        for (int j = i + 1; j <= n; j ++) {
            if (a[j] <= a[i]) {
                minn = j;//找到下一个要去加油的站
                break;
            }
        }
        if (V < 0) V = 0;
        int x = (s[minn] - s[i] + m - 1 - V) / m;//计算
        ans += x * a[i];

        // cout << minn << " " << i << " " << x * a[i] << " " << V << "\n";
        V = x * m - ((s[minn] - s[i] - V));
        i = minn;
        // cout << s[minn] - s[i - 1] << " " << minn << " " << i << "\n";
    }
    cout << ans;
    return 0;
}

一元二次方程

模拟题,就是题面对初一及以下的人有点不友好。

其实很见到,难点也就是输出实数。

#include <bits/stdc++.h>

using namespace std;
/*
*/
int T, M; 
void printnum(int p, int q, char ch) {
    double x = p * 1.0 / 1.0 / q;
    if (x == (int)x) {
        cout << x << ch;
    } else {
        int gpq = __gcd(p, q);
        gpq = abs(gpq);
        cout << p / gpq << "/" << q / gpq << ch;
    }
}
void printnum2(int p, int q) {
    double x = p * 1.0 / 1.0 / q;
    if (x == (int)x) {
        if (x != 0) cout << x << "+";
    } else {
        int gpq = __gcd(p, q);
        gpq = abs(gpq);
        cout << p / gpq << "/" << q / gpq << "+";
    }
}
void printnum3(int p, int q, int sq) {
    // cout << p << " " << q << " " << sq << "\n";
    double x = p * 1.0 / 1.0 / q;
    if (x == (int)x) {
        if (x != 1) cout << x << "*sqrt(" << sq << ")\n";
        else cout << "sqrt(" << sq << ")\n";
    } else {
        int gpq = __gcd(p, q);
        gpq = abs(gpq);
        // cout << "+";
        if (p / gpq != 1) cout << p / gpq << "*sqrt(" << sq << ")/" << q / gpq << "\n";
        else cout << "sqrt(" << sq << ")/" << q / gpq << "\n";
    }
}
int main() {
    // ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin >> T >> M;
    while(T --) {
        int a, b, c; cin >> a >> b >> c;
        if (a < 0) a = -a, b = -b, c = -c;
        if (b * b - 4 * a * c < 0) {
            cout << "NO\n";
            continue;
        }
        int del = b * b - 4 * a * c;
        if (int(sqrt(del)) * int(sqrt(del)) == del) {
            // cout << -b + int(sqrt(del)) << " " << 2 * a << "\n";
            printnum(-b + int(sqrt(del)), 2 * a, '\n');
        } else {
            // cout << "*" << "\n";
            printnum2(-b, 2 * a);
            int p2 = 1;
            for (int i = 1; i * i <= del; i ++) {
                if (del % (i * i) == 0) {
                    p2 = i;
                }
            }
            if (p2 == 1) {

                cout << "sqrt(" << del << ")/" << 2 * a << "\n";
            } else {
                printnum3(p2, 2 * a, del / p2 / p2);
            }
        }
    }
    return 0;
}

旅游巴士

图论题。

运用算法:dijkstra。

其实说是 dijkstra,但是实际上就是优先队列优化 bfs。

题目的难点就是转换,把题目变成一个图论模型。

我们定义 $dp_{i,j}$ 为到达第 $i$ 个点,用时模 $k$ 余 $j$,需要用的最短时间

对于每个优先队列的结构体:

struct N {
    int v, i, d;
    bool operator <(N y) const {
        return d > y.d;
    }
};

其中 v 为节点,i 为用时模 $k$,d 为总用时。

也就是 $dp_{v, i} = d$。

但是,我们发现题目有一个限制:

游客只有不早于 $a_i$ 时刻才能通过这条道路。

我们可以等一会再出发,这样就行了,设目前时间是 $t$,那么延后 $\lfloor\frac{a_i – t}{k}\rfloor \times k$ 就行了。

代码

#include <bits/stdc++.h>
using namespace std;
int n, m, k;
vector <int> e[100005];
int t[100005], dp[10005][105], vis[10005][105];
map <pair <int, int>, int> mp;
#define mkp make_pair

struct N {
    int v, i, d;
    bool operator <(N y) const {
        return d > y.d;
    }//重载运算符,使得优先队列是从小到大
};

int main() {
    cin >> n >> m >> k;

    for (int i = 1; i <= m; i ++) {
        int x, y, z;
        cin >> x >> y >> z;
        e[x].push_back(y);
        t[i] = z;
        mp[make_pair(x, y)] = i;
    }

    priority_queue <N> q;
    memset(dp, 0x7f, sizeof(dp));
    q.push((N) {
        1, 0, 0
    });
    dp[1][0] = 0;

    while (q.size()) {
        int vv = q.top().v;
        int ii = q.top().i;
        q.pop();//弹出

        if (vis[vv][ii])
            continue;//走过的

        vis[vv][ii] = 1;
//      cout << vv << " " << ii << "\n";

        for (int i = 0; i < e[vv].size(); i ++) {//遍历下一个可以去的节点
            int ww = e[vv][i];
            int tt = t[mp[mkp(vv, ww)]];
            int j = (ii + 1) % k;
            int t = dp[vv][ii];
//          cout << vv << " " << ww << " " << ii << " " << j << " " << t << " " << tt << " " << dp[ww][ii] << "\n";

            if (t < tt) {
                t += (tt - t + k - 1) / k * k;
            }

            if (dp[ww][j] > t + 1)
                dp[ww][j] = t + 1, q.push((N) {
                ww, j, t + 1
            });//继续 bfs
        }
    }

    if (dp[n][0] != dp[n + 1][0]) cout << dp[n][0];
    else cout << "-1";
}
本文链接:https://ztrztr.top/archives/117
版权声明:本文 《CSP-J 2023 题解》 为 ztrztr 原创。著作权归作者所有。
转载说明:联系作者或者评论区留言获得转载授权,并注明转载地址。
暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇