2 条题解

  • 4
    @ 2022-10-18 18:03:21

    额外拨动开关,则该时间点之后所有原来的亮灯时间变为熄灯时间,熄灯时间变为亮灯时间,即交换了亮熄灯时间。

    所以若是某次拨动开关的时间点之后的总熄灯时间大于总亮灯时间,我们可以在该时间点之后额外添加一个拨动开关的时间点,后边的总亮灯时间和总灭灯时间就会交换,这样总体亮灯时间就会变长

    所以我们只需要从数组的末尾开始遍历,找哪个拨动开关的时间点a[i]后边的总熄灯时间-总亮灯时间为正值且差值最大,就在这个时间点a[i]后边相邻的时间点额外拨动一次开关交换后边的熄灯和亮灯时间,这样最长亮灯时间就=该a[i]点前边的总亮灯时间+该a[i]点之后的总灭灯时间-1(相邻两个时间点之间的灯的状态并未改变)

    当然,若是每次拨动开关的点位之后的总熄灯时间-总亮灯时间为负值,则不用额外添加拨动开关。

    核心代码:

     //输入并计算存取每个点前边总开灯时间
            for(i=1;i<=n;i++)
            {
                scanf("%d",&x[i]);
                if(i%2==1)k+=x[i]-x[i-1];
                y[i]=k;
            } 
            //计算并存取每个点后边总关灯时间
            x[n+1]=m;
            int g=0;//总关灯时间
            k=0;
            int cha;//每个点后边关灯时间-开灯时间的差值
            int max=0;//最大差值
            int maxn;//最大差值点  
            for(i=n;i>=0;i--)
            {
                if(i%2==0)
                    k+=x[i+1]-x[i];
                else
                    g+=x[i+1]-x[i];
                z[i]=g;  
                cha=g-k;  
                if(cha>max)
                {
                    max=cha;
                    maxn=i;
                }      
            }
    
    • 2
      @ 2022-10-15 21:25:55

      这题虽然题目写的是二分,但是实际正解和二分没啥关系,是前缀和的预处理问题,想明白开关灯的状态就行了。

      画图理解如下:

      tu1

      tu2

      操作是n段内每一段都加入操作判断一下。

      核心代码:

      //  s1 奇数前缀和, s2偶数前缀和(奇数代表d区间,偶数代表L区间)
      for(int i =1; i <= n ; i++) cin>>a[i];
              a[++n] = m;     //把m看成是一个时刻,把它放到a[n+1]里
              s1[n]  = s2[n] = 0;
              for(int i = n-1 ; i >= 0 ; i--)
              {
                  s1[i] = s1[i+1];
                  s2[i] = s2[i+1];
                  if(i % 2 == 0 ) s1[i] += a[i + 1] - a[i];
                  else s2[i] += a[i + 1] - a[i];
              }
              int ans = s1[0];     //一次都不按的灯亮时间总长度,注意此处维护的是后缀和 所以下标是0
              for(int i = 0 ; i < n ; i++)    // 从前往后枚举每个区间怎么按
              {
                  int t = a[i + 1] - a[i];    // 求一下当前区间的长度
                  if( t == 1) continue;       //如果当前区间亮灯长度 已经是1了
                  ans = max(ans, s1[0] - s1[i]  + s2[i+1] + t -1);    // s1[0] - s1[i] 是前面的奇数区间
      ​
              }
      
      • 1

      信息

      ID
      816
      时间
      1000ms
      内存
      256MiB
      难度
      8
      标签
      递交数
      64
      已通过
      10
      上传者