宝石传递

解题思路

这是一个环形传递问题,N个生物围成一圈,每个生物i有两个属性:

  1. s[i]:收到宝石后传递给下一个生物所需的时间

  2. t[i]:上帝直接给该生物宝石的时间

我们需要计算每个生物第一次收到宝石的时间。关键点在于:

  1. 宝石可以通过两种方式到达:直接来自上帝,或者来自前一个生物

  2. 因为是环形结构,可能需要绕环多次才能确定最优解

代码注释


#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10, inf = 0x3f3f3f3f; // 定义常量,N为最大可能值+10,inf为无穷大

int n;          // 生物数量
int dis[N];     // 存储每个生物第一次收到宝石的时间
int s[N], t[N]; // s[i]表示传递时间,t[i]表示直接接收时间

int main()
{
    // 输入处理
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> s[i];      // 输入每个生物的传递时间
    for(int i = 1; i <= n; i++) {
        cin >> t[i];          // 输入直接接收时间
        dis[i] = t[i];        // 初始化dis数组,默认第一次接收时间就是直接接收时间
    }
    
    // 第一轮环形处理
    dis[0] = t[n]; // 将第0位设为最后一个生物的值,方便环形处理
    s[0] = s[n];   // 同上
    t[0] = t[n];   // 同上
    
    for(int i = 1; i <= n; i++) {
        // 比较两种方式:直接接收 vs 从前一个生物传递过来
        dis[i] = min(dis[i], dis[i - 1] + s[i - 1]);
    }
    
    // 第二轮环形处理(确保环形结构中的最优解能够完全传播)
    dis[0] = dis[n]; // 更新第0位的值为处理后的最后一个生物的值
    s[0] = s[n];     // 同上
    t[0] = t[n];     // 同上
    
    for(int i = 1; i <= n; i++) {
        // 再次比较更新
        dis[i] = min(dis[i], dis[i - 1] + s[i - 1]);
        cout << dis[i] << endl; // 输出最终结果
    }
    
    return 0;
}

算法分析

  1. 初始化:每个生物的初始接收时间设为Takahashi直接给的时间t[i]

  2. 第一轮处理

    • 从第一个生物开始,比较"直接接收时间"和"前一个生物传递过来的时间"

    • 更新每个生物的最早接收时间

  3. 第二轮处理

    • 因为环形结构,一轮处理可能不足以传播所有最优解

    • 再次遍历确保最优解完全传播

  4. 输出结果:经过两轮处理后,dis[i]即为每个生物第一次收到宝石的最早时间

为什么需要两轮处理?

考虑环形结构中,最优解可能需要绕环一周才能完全传播。例如:

  • 生物1的最优解可能依赖于生物N的最优解

  • 第一轮处理时,生物N的最优解可能还未计算完成

  • 第二轮处理确保所有依赖关系都得到满足

时间复杂度

  • 两轮线性遍历,时间复杂度为O(N)

  • 完全满足题目中N≤200000的要求

 

posted @ 2025-04-29 17:46  行胜于言Ibl  阅读(40)  评论(0)    收藏  举报