1997. 访问完所有房间的第一天 (C++)

文章描述了一个C++编程问题,涉及一个名为Solution的类,用于计算从第一天开始访问所有房间的天数。状态转移规则基于当前房间访问次数:奇数次后下一天访问nextVisit中的房间,偶数次则访问下一个房间。文章详细解释了递推公式并给出了最终的简化版本。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一行状态转移 C++代码

class Solution {
public:
    int firstDayBeenInAllRooms(vector<int>& nextVisit) {
        const int MOD = 1'000'000'007;
        int n = nextVisit.size();
        vector<long> f(n,0);

        for (int i = 1; i < n; ++i)
            f[i] = (2*f[i-1] - f[nextVisit[i-1]] + 2 + MOD) % MOD;
 
        return f[n-1];

    }
};

下一次访问 哪个房间由 访问当前房间的次数 决定

        算上本次访问 访问当前房间的次数为奇数 则第二天访问的房间在nextVisit数组内

        且nextVisit数组中 索引对应的房间号 总是小于等于索引 如 第4 个元素 对应的房间号 永远不可能大于4

        算上本次访问 访问当前房间的次数为偶数 则第二天访问的房间为 (i + 1) % n

        状态定义:f[i] 第一次访问i房间时为第f[i]天。

        首先,访问第i个房间一定是 当i-1个房间的访问次数为偶数,那么下一天访问的才是第i个房间,并且第一次访问第i个房间,一定是第i-1个房间第二次被访问的下一天,则有:

        第一次访问 i 房间的天数 f1[i] = 第二次访问 i - 1 房间的天数f2[i-1] + 1

对第二次访问i-1房间的天数f2[i-1]分类讨论:

        如果 nextVisit[i-1] = i-1,即当访问i-1个房间的次数为奇数的时候,下一天访问的房间还是第i-1个房间,则第二次访问i-1房间的天数就是第一次访问i-1房间天数加1:

        f2[i-1] = f1[i-1] + 1

        如果 nextVisit[i-1] < i - 1,这说明当访问第i-1个房间之后,下一天访问的房间不再是第i-1个房间,而是另一个房间号比较小的房间,其房间号为nextVisit[i-1],那么我们要考虑的就是,从第nextVisit[i-1]个房间再次回到第i-1个房间需要多少天?首先,上一行情况下到达第nextVisit[i-1]个房间的天数为f1[i-1] + 1,即到达第i-1个房间之后,又过了一天。再次回到刚刚的问题,从第nextVisit[i-1]个房间再次回到第i-1个房间需要多少天?这是本题的重点,由于访问偶数次才能访问右边的下一个房间,所以对于i左边的房间,我们一定都访问了偶数次(不然不可能到达i)。所以,在都是偶数次的情况下,可以把他们都看作0次,这样整个过程就跟一开始的过程完全一样了,那么从第nextVisit[i-1]房间到i-1房间过去的天数就等于第一次访问第i-1个房间的天数减去第一次访问第nextVisit[i-1]的天数: f1[i-1] - f1[nextVisit[i-1]],具体过程如下

        f2[i-1] = f1[i-1] + 1 +  f1[i-1] - f1[nextVisit[i-1]]

                = 2 * f1[i-1] - f1[nextVisit[i-1]] + 1

      由于f2完全依赖f1,所以简化递推公式为:

        f[n] = f[n-1] + 2 if nextVisit[n-1] == n - 1

        f[n] = 2*f[n-1] - f[nextVisit[n-1]] + 2 if nextVisit[n-1] < n - 1

       合并到一起就是:
        f[n] = 2*f[n-1] - f[nextVisit[n-1]] + 2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值