luogu-P1161 开灯

luogu-P1161 开灯

GESP C++三级练习,一维数组练习,难度★★☆☆☆。

luogu-P1161 开灯

题目要求

题目描述

在一条无限长的路上,有一排无限长的路灯,编号为 1,2,3,4,1,2,3,4,\dots

每一盏灯只有两种可能的状态,开或者关。如果按一下某一盏灯的开关,那么这盏灯的状态将发生改变。如果原来是开,将变成关。如果原来是关,将变成开。

在刚开始的时候,所有的灯都是关的。小明每次可以进行如下的操作:

指定两个数,a,ta,taa 为实数,tt 为正整数)。将编号为 a,2×a,3×a,,t×a\lfloor a\rfloor,\lfloor 2 \times a\rfloor,\lfloor3 \times a\rfloor,\dots,\lfloor t \times a\rfloor 的灯的开关各按一次。其中 k\lfloor k \rfloor 表示实数 kk 的整数部分。

在小明进行了 nn 次操作后,小明突然发现,这个时候只有一盏灯是开的,小明很想知道这盏灯的编号,可是这盏灯离小明太远了,小明看不清编号是多少。

幸好,小明还记得之前的 nn 次操作。于是小明找到了你,你能帮他计算出这盏开着的灯的编号吗?

输入格式

第一行一个正整数 nn,表示 nn 次操作。

接下来有 nn 行,每行两个数,ai,tia_i,t_i。其中 aia_i 是实数,小数点后一定有 66 位,tit_i 是正整数。

输出格式

仅一个正整数,那盏开着的灯的编号。

输入输出样例 #1

输入 #1

3
1.618034 13
2.618034 7
1.000000 21

输出 #1

20

说明/提示

T=i=1nti=t1+t2+t3++tnT=\sum \limits_{i=1}^n t_i = t_1+t_2+t_3+\dots+t_n

  • 对于 30%30\% 的数据,满足 T1000T \le 1000
  • 对于 80%80\% 的数据,满足 T200000T \le 200000
  • 对于 100%100\% 的数据,满足 T2000000T \le 2000000
  • 对于 100%100\% 的数据,满足 n5000n \le 50001ai<10001 \le a_i<10001tiT1 \le t_i \le T

数据保证,在经过 nn 次操作后,有且只有一盏灯是开的,不必判错。而且对于所有的 ii 来说,ti×ait_i\times a_i 的最大值不超过 20000002000000


题目分析

解题思路

本题的解题思路如下:

  1. 问题本质:

    • 给定一系列操作,每次操作会按指定规则改变一些灯的状态
    • 每个操作包含两个参数:实数 aa 和正整数 tt
    • 每次操作会改变编号为 a\lfloor a \rfloor, 2×a\lfloor 2 \times a \rfloor, …, t×a\lfloor t \times a \rfloor 的灯的状态
    • 最终只有一盏灯是亮着的,需要找出这盏灯的编号
  2. 解题关键:

    • 核心思路 - 状态模拟:
      1. 使用数组记录每盏灯的状态:
        • 创建一个足够大的数组 arrayarray(根据题目提示 20000052000005 大小足够)
        • 00 表示灯是关闭的,11 表示灯是打开的
      2. 模拟每次操作:
        • 对于每次操作的参数 aatt
        • 计算需要改变状态的灯的编号:i×a\lfloor i \times a \rfloor (ii11tt)
        • 使用异或操作(1\oplus 1)切换对应灯的状态
      3. 最后遍历数组,找到值为 11 的位置,即为答案
  3. 复杂度分析:

    • 时间复杂度:O(n×tmax)O(n \times t_{max}),其中n为操作次数,t_max为单次操作最大次数
    • 空间复杂度:O(2000005)O(2000005),需要一个固定大小的数组存储灯的状态

{% include custom/custom-post-content-inner.html %}


示例代码

#include <iostream>

// 用于存储每个灯的状态的数组,0表示关闭,1表示打开
int array[2000005];
int main() {
    // n表示操作次数
    int n;
    std::cin >> n;
    // 循环处理每次操作
    for (int i=0; i < n; i++) {
        // a为实数倍数,t为操作次数上限
        double a;
        int t;
        std::cin >> a >> t;
        // 对于每次操作,计算需要改变状态的灯的编号
        for (int j = 1; j <=t; j++) {
            // 计算当前需要改变状态的灯的编号
            int idx = a * j;
            // 使用异或操作切换灯的状态(0变1,1变0)
            array[idx] ^= 1;
        }
    }
    // 遍历所有可能的灯,找出唯一一个打开的灯
    for (int i=0; i < 2000005; i++) {
        // 如果找到值为1的位置,说明这盏灯是打开的
        if (array[i] == 1) {
            std::cout << i << " ";
        }
    }
    return 0;
}             

{% include custom/custom-post-content-footer.md %}

所有代码已上传至Github:https://github.com/lihongzheshuai/yummy-code

luogu-”系列题目可在 洛谷题库 在线评测。

bcqm-”系列题目可在 编程启蒙题库 在线评测。

GESP/CSP 认证学习微信公众号
GESP/CSP 认证学习微信公众号
Last updated on