• 2023-CSPJ 题解


    2023-CSPJ

    T1. 小苹果

    考虑第一问,注意到每次去走一些数字后会变成另一个子问题,且 n ′ ≤ 2 3 n n'\leq \frac{2}{3}n n32n,故暴力维护即可。

    对于第二问,用同样的办法,暴力维护 n n n 的标号即可。

    Code 100pts

    #include 
    using namespace std;
    typedef long long LL;
    typedef pair<int, int> PII;
    inline int read()
    {
        int x = 0, f = 1;
        char s = getchar();
        while (s < '0' || s > '9')
        {
            if (s == '-')
                f = -f;
            s = getchar();
        }
        while (s >= '0' && s <= '9')
        {
            x = (x << 3) + (x << 1) + (s ^ 48);
            s = getchar();
        }
        return x * f;
    }
    
    int main()
    {
        // freopen("in.txt", "r", stdin);   //输入重定向,目录下的in.txt文件中读取
        // freopen("out.txt", "w", stdout); //输出重定向,目录下的out.txt文件中
    
        int n = read();
    
        int cnt = 0,  res = 0;
    
        while (n)
        {
            cnt++;
            int k = (n - 1) % 3;
            if (res == 0 && k == 0)
                res = cnt;
            n = n - 1 - (n - 1) / 3; // 每次减少的数量。
        }
        cout << cnt << ' ' << res;
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    T2.公路

    考虑贪心,对于每个加油站,找到下一个比他便宜的油站,每次在这个位置加尽可能少的油,使得能顺利开到到下一个比他便宜的油站,一路贪心下去就可以了。注意开long long

    拓展一下: 题目中的车的油桶是无限的。 如果现限制油桶容积这需要考虑新的算法。 用单调栈

    Code 100pts

    #include 
    using namespace std;
    typedef long long LL;
    
    const int N = 2e5 + 10;
    int n, d;
    
    LL v[N], a[N]; // v[i] 代表i-i+1 的距离, a[i] 代表第i个站点的油价a[i]
    
    inline int read()
    {
        int x = 0, f = 1;
        char s = getchar();
        while (s < '0' || s > '9')
        {
            if (s == '-')
                f = -f;
            s = getchar();
        }
        while (s >= '0' && s <= '9')
        {
            x = (x << 3) + (x << 1) + (s ^ 48);
            s = getchar();
        }
        return x * f;
    }
    
    int main()
    {
        // freopen("in.txt", "r", stdin);   //输入重定向,目录下的in.txt文件中读取
        // freopen("out.txt", "w", stdout); //输出重定向,目录下的out.txt文件中
        n = read(), d = read();
        for (int i = 1; i < n; i++)
            cin >> v[i];
        for (int i = 1; i <= n; i++)
            cin >> a[i];
        LL ans = 0;
        LL best = 1e6;
        LL dis = 0;
        for (int i = 1; i <= n; i++)
        {
            best = min(a[i], best); // 选择最优的油价前往下一个目的地。
            dis += v[i];            // 下个目的地还需要加多少油,因为前面一次加油肯定有剩下油。
            LL oil = (dis + d - 1) / d;         //确认下这次加油数量,上取整计算。
            ans += (dis + d - 1) / d * best;    //更新下答案。
            dis -= oil * d;                     // 注意我们需要更新下dis,
            // cout << best << ' ' << ans << endl; //
        }
        cout << ans << endl;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    T3. 一元二次方程

    根据题意模拟即可。取得50分比较容易。即符合条件C,但是拿满分比较难,需要注意比较多的细节代码。

    Code 50pts

    #include 
    using namespace std;
    typedef long long LL;
    typedef pair<int, int> PII;
    int t, m;
    inline int read()
    {
        int x = 0, f = 1;
        char s = getchar();
        while (s < '0' || s > '9')
        {
            if (s == '-')
                f = -f;
            s = getchar();
        }
        while (s >= '0' && s <= '9')
        {
            x = (x << 3) + (x << 1) + (s ^ 48);
            s = getchar();
        }
        return x * f;
    }
    
    
    void solve(int a, int b, int c)
    {
        int delta = b * b - 4 * a * c;
    
        // 无根的情况先处理。
        if (delta < 0)
        {
            cout << "NO" << endl;
            return;
        }
    
        // 剩下有根的情况需要讨论啦。
        // 首先把a>0 的情况和a<0 的情况分开讨论。
        if (a > 0)
        {
    
            int res = (-b + (int)sqrt(delta)) / (2 * a);
            cout << res << endl;
            return;
        }
        else
        {
            int res = (-b - (int)sqrt(delta)) / (2 * a);
            cout << res << endl;
            return;
        }
    }
    
    int main()
    {
        // freopen("in.txt", "r", stdin);   //输入重定向,目录下的in.txt文件中读取
        // freopen("out.txt", "w", stdout); //输出重定向,目录下的out.txt文件中
    
        t = read(), m = read();
        while (t--)
        {
            int a = read(), b = read(), c = read();
            solve(a, b, c);
        }
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    Code 100pts

    #include 
    using namespace std;
    
    // 输出一个有理数
    void print(int fz, int fm)
    {
        int g = abs(__gcd(fz, fm));
        fz /= g, fm /= g;
        if (fm == 1)
            printf("%d", fz);
        else
            printf("%d/%d", fz, fm);
    }
    int main()
    {
        int _;
        scanf("%d%*d", &_);
        while (_--)
        {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            int d = b * b - 4 * a * c;
            if (d < 0)
                printf("NO");
            else
            {
                int x = 0;
                for (int i = 1; i * i <= d; i++)
                {
                    if (d % (i * i) == 0)
                        x = i;
                }
                if (x * x == d)
                {
                    int fz, fm;
                    if (a > 0)
                        fz = -b + x, fm = 2 * a;
                    else
                        fz = b + x, fm = -2 * a;
                    print(fz, fm);
                }
                else
                {
                    int fz, fm;
                    if (a > 0)
                        fz = -b, fm = 2 * a;
                    else
                        fz = b, fm = -2 * a;
                    if (fz != 0)
                    {
                        print(fz, fm);
                        putchar('+');
                    }
                    int r = d / (x * x);
                    if (a > 0)
                        fz = x, fm = 2 * a;
                    else
                        fz = x, fm = -2 * a;
                    int g = __gcd(fz, fm);
                    fz /= g, fm /= g;
                    if (fm == 1)
                    {
                        if (fz == 1)
                            printf("sqrt(%d)", r);
                        else
                            printf("%d*sqrt(%d)", fz, r);
                    }
                    else if (fz == 1)
                    {
                        printf("sqrt(%d)/%d", r, fm);
                    }
                    else
                    {
                        printf("%d*sqrt(%d)/%d", fz, r, fm);
                    }
                }
            }
            puts("");
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    T4. 旅游巴士

    考虑拆点,把一个点 u u u 拆成 ( u , 0 ∼ k − 1 ) (u,0\sim k-1) (u,0k1),若原图存在一条 u → v u\to v uv 的边,那么新图上则有 ( u , x ) → ( v , ( x + 1 )   m o d   k ) (u,x)\to (v,(x+1)\bmod k) (u,x)(v,(x+1)modk)

    那么问题转化成求 ( 1 , 0 ) → ( n , 0 ) (1,0)\to (n,0) (1,0)(n,0) 的最短路。

    考虑边的限制怎么解决,注意到我们可以任选开局的时机,因此如果在一个位置被卡住了,可以通过不断加 k k k 直到满足边的时间限制,走回头路一定不优,这个过程用一次 dij 实现即可实现。

    时间复杂度 O ( n k log ⁡ ( m k ) ) \mathcal{O}(nk\log (mk)) O(nklog(mk))

    此外,注意到到达时间越晚,关于边的限制也就越松,因此可以拆点后二分到达时间然后倒着 bfs

    Code 100pts

    #include 
    using namespace std;
    const int INF = 0x3f3f3f3f;
    const int N = 10005;
    
    vector<pair<int, int>> G[N];
    int d[N][105];
    int vis[N][105];
    struct Node
    {
        int u, i, d;
        bool operator<(const Node &rhs) const
        {
            return d > rhs.d;
        }
    };
    int main()
    {
        int n, m, kk;
        scanf("%d%d%d", &n, &m, &kk);
        while (m--)
        {
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            G[u].push_back({v, w});
        }
        memset(d, 0x3f, sizeof d);
        priority_queue<Node> q;
        q.push({1, 0, d[1][0] = 0});
        while (q.size())
        {
            int u = q.top().u, i = q.top().i;
            q.pop();
            if (vis[u][i])
                continue;
            vis[u][i] = 1;
            for (auto [v, w] : G[u])
            {
                int t = d[u][i], j = (i + 1) % kk;
                if (t < w)
                    t += (w - t + kk - 1) / kk * kk;
                if (d[v][j] > t + 1)
                    q.push({v, j, d[v][j] = t + 1});
            }
        }
        if (d[n][0] == INF)
            d[n][0] = -1;
        printf("%d\n", d[n][0]);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
  • 相关阅读:
    [SQL开发笔记]WHERE子句 : 用于提取满足指定条件的记录
    如何将48位立即数加载到ARM通用寄存器中?
    【云原生之kubernetes】在kubernetes集群下的jobs与cronjobs管理
    三、@RequestMapping注解
    计算机操作系统原理第七、八章习题
    elasticsearch.yml基本配置说明
    Unity脚本判断场景内物体是否为Root Prefab的方法
    风控数据(模型)不扎心,只因好这道流水工序上的处理技巧
    WMWS在线监测管理系统的工程常用计算工具
    java之泛型
  • 原文地址:https://blog.csdn.net/weixin_51184047/article/details/133999879