Codeforces 1000B Light It Up(思维)

B. Light It Up

题目大意:有一盏灯,在0时刻亮起,M时刻关闭。在一些时刻有一些开关可以改变灯的状态(开-->关,关-->开)。给你一个机会再0~m任何一个时刻(不与a[i]相同)加一个开关,求灯亮着的最大时间。

显然应该把这个开关安排在任何一个a[i]的相邻位置(左边或右边),这样浪费的时间会最少。然而无论在左边还是右边,两个情况都是同一个道理,所以我们只需要考虑放在a[i]左边相邻的一种情况。

这题的妙处就是:无论在哪添加这个开关,每个开关对于改变灯的状态都会改变。

Eg:如果这个开关原本会把灯关掉,那么添加开关后它会让灯亮。

我们处理一个b[i]前缀和数组,表示a[i]时刻前灯亮的时间;c[i]前缀和数组表示a[i]时刻后灯关着的时间;

那么当把灯放在a[i]-1时刻时,只会影响a[i]前面灯亮着的时间少了1,而后面亮着的时间再此时由未添加开关时的b[n]-b[i]变成了c[n]-c[i] (因为a[i]后每个开关对于改变灯的状态改变,关--开);

m可以看做一个时刻算到b[n+1],c[n+1]中,所以在a[i]-1处添加开关的贡献是b[i]-1+c[n+1]-c[i],扫一遍维护最大值。

由于可以不加开关,还要将答案与不加开关的时间比较。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cmath>
 5 #include <queue>
 6 #define ll long long
 7 #define out(a) printf("%d ",a)
 8 using namespace std;
 9 int n,m;
10 int a[100050],b[100050],c[100050];
11 int now,ans,sum;
12 int read()
13 {
14 int s=0,t=1; char c;
15   while (c<'0'||c>'9'){if (c=='-') t=-1; c=getchar();}
16   while (c>='0'&&c<='9'){s=s*10+c-'0'; c=getchar();}
17   return s*t;
18 }
19 int main()
20 {
21 n=read(); m=read(); ans=-2333333;
22 for (int i=1;i<=n;i++){
23   a[i]=read(); b[i]=b[i-1]; c[i]=c[i-1];
24   if (i&1) b[i]+=a[i]-a[i-1],sum+=a[i]-a[i-1];
25   else c[i]+=a[i]-a[i-1];
26     }
27     if (n&1) b[n+1]=b[n],c[n+1]=c[n]+m-a[n];
28     else b[n+1]=b[n]+m-a[n],c[n+1]=c[n],sum+=m-a[n];
29     for (int i=1;i<=n+1;i++)
30       now=b[i]+c[n+1]-c[i]-1,ans=max(now,ans);
31       ans=max(ans,sum);
32     out(ans);
33     return 0;
34 }
View Code
原文地址:https://www.cnblogs.com/Kaleidoscope233/p/9277271.html