csp-j2022-2023解析

P9748 [CSP-J 2023] 小苹果

这个问题可以通过数学分析来解决。我们需要找到一个规律,描述每天拿走的苹果编号以及最终拿走所有苹果所需的天数。

首先,我们注意到小苞每天拿走的苹果编号形成了一个等差数列,公差为2。第一天拿走的苹果编号为 1 , 3 , 5 , . . . , n − 1 1, 3, 5, ..., n-1 1,3,5,...,n1(如果n是偶数),或者1, 3, 5, … (如果n是奇数)。我们可以发现,每天拿走的苹果数量也是等差的,第一天拿走 n / 2 n/2 n/2
第二天拿走 ( n − 2 ) / 2 (n-2)/2 (n2)/2个,以此类推。

接下来,我们需要找到一个方法来计算拿走编号为n的苹果所需的天数。这可以通过观察苹果编号的模式来实现。对于编号为 n n n的苹果,它在第一天之后剩下的位置是 2 2 2的幂次方的倍数。例如,如果
n = 8 n=8 n=8,那么在第一天之后,编号为8的苹果的位置是 4 (即 2 2 ) 4(即2^2) 4(即22,在第二天之后的位置是 2 (即 2 1 ) 2(即2^1) 2(即21,在第三天之后的位置是1 (即 2 0 ) (即2^0) (即20。因此,我们可以得出结论,编号为
n n n的苹果会在位置变为1的那一天被拿走。

我们可以使用对数来计算这个过程。如果n是2的幂次方,那么拿走所有苹果所需的天数就是 l o g 2 ( n ) log2(n) log2(n)。如果 n 不是 2 n不是2 n不是2的幂次方,我们可以找到最接近 n n n的小于 n n n 2 2 2的幂次方数,然后计算从这个数到 n n n需要额外拿的天数。

以下是C++代码:

#include 
#include 

using namespace std;

int main() {
   
    long long n;
    cin >> n;

    // 计算拿走所有苹果所需的天数
    int days = 0;
    long long pow = 1;
    while (pow < n) {
   
        pow <<= 1; // 等同于 pow = pow * 2
        ++days;
    }

    // 计算编号为n的苹果被拿走的天数
    int dayOfN = log2(n);
    if (n & (n - 1)) {
   
        // 如果n不是2的幂次方,我们需要额外计算
        dayOfN += 1;
    }

    cout << days << " " << dayOfN << endl;

    return 0;
}

根据样例输入 #1,这段代码应该输出:

5 5

这表示需要5天才能拿走所有的苹果,而编号为8的苹果会在第5天被拿走。

P9751 [CSP-J 2023] 旅游巴士

为了解决这个问题,我们可以使用广度优先搜索(DFS)算法。DFS 是一种遍历图的算法,它从一个节点开始,逐层访问图中的所有节点。在这个问题中,我们可以将每个地点视为图中的一个节点,每条道路视为连接两个节点的边。

我们需要根据道路的开放时间来更新图中边的权重。如果一条边的开放时间大于当前时间,那么在这条边之前,我们不能通过它。因此,我们可以将开放时间作为边的权重,只有当当前时间大于或等于这个权重时,我们才能通过这条边。

以下是C++代码的实现:

#include 
#include 
#include 
#include 

using namespace std;

const int INF = 1e9; // 定义一个足够大的数表示无穷大

// 邻接表表示图
vector<vector<pair<int, int>>> graph(n + 1);
// 存储每个节点的最早访问时间
vector<int> dist(n + 1, INF);
// 起点和终点
int start = 1, end = n;

// BFS 函数
void bfs() {
   
    queue<int> q;
    q.push(start); // 将起点加入队列
    dist[start] = 0; // 起点的最早访问时间为0

    while (!q.empty()) {
   
        int u = q.front();
        q.pop();

        for (auto& edge : graph[u]) {
   
            int v = edge.first;
            int weight = edge.second;

            if (dist[v] > dist[u] + weight) {
   
                // 更新最早访问时间
                dist[v] = dist[u] + weight;
                q.push(v);
            }
        }
    }

    // 如果终点的最早访问时间没有改变,说明没有可达路径
    if (dist[end] == INF) {
   
        cout << -1 << endl;
    } else {
   
        // 计算最早离开景区的时间,需要加上k的倍数
        int leaveTime = (dist[end] + k - 1) / k * k;
        cout << leaveTime << endl;
    }
}

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

    // 读取每条道路信息
    for (int i = 0; i < m; ++i) {
   
        int u, v, a;
        cin >> u >> v >> a;
        graph[u].push_back({
   v, a}); // 添加有向边
    }

    bfs(); // 执行BFS算法

    return 0;
}

这段代码首先定义了一个邻接表graph来表示图,并定义了一个dist数组来存储每个节点的最早访问时间。然后,我们使用BFS算法遍历图,更新每个节点的最早访问时间。最后,我们根据终点的最早访问时间计算最早离开景区的时间,并输出结果。

根据样例输入 #1,这段代码应该输出 6,表示小 Z 最早可以在第 6 个时间单位乘坐旅游巴士离开景区。

P9749 [CSP-J 2023] 公路

为了解决这个问题,我们可以采用动态规划的方法。我们定义一个数组 cost[i] 来表示从站点 1 到站点 i 的最小加油花费。我们从站点 1 开始,逐步计算到达每个后续站点的最小花费。

在计算站点 i 的 cost[i] 时,我们需要考虑从之前的每个站点 j (j < i) 到达 i 的情况。对于每个 j,我们需要计算在站点 j 加油所需的花费,以及从 j 到 i 之间需要的油量。我们需要保证在 j 站点加的油足够到达 i 站点,并且选择花费最小的方案。

以下是C++代码的实现:

#include 

你可能感兴趣的:(算法,c++,开发语言)