[贪心] aw3774. 亮灯时长(思维+后缀和+代码细节+CF1000B)
Posted Ypuyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[贪心] aw3774. 亮灯时长(思维+后缀和+代码细节+CF1000B)相关的知识,希望对你有一定的参考价值。
1. 题目来源
链接:3774. 亮灯时长
题解:
2. 题目解析
CF1000 B
分析后并不难,但是死于代码实现上。
区间由两点分割,且下标从 0 开始,前缀和维护一个区间和,一开始总以为前缀和没从 1 开始,不太方便做,但是实际上并不需要这样考虑。
以下标 i
分成总共 n+1
个区间段,i
从 1 开始到 n+1
,直接做前缀和即可,light[1]-light[0]
就是区间 [0,1]
的区间和,也将其看成第一个奇数区间。详见大佬题解:清晰的代码,前缀和照样做。
那么这个前缀和就很好表示了,一段区间长度就是 a[i]-a[i-1]
,当 i%2==0
时,这个区间就是偶数区间,否则就是奇数区间,维护一个前缀和就行了。
要注意这个维护前缀合的方式,很不错。并且注意后缀和的写法,有时候两者需要同时使用。
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)
后缀和:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PLL;
int n, k;
int main() {
cin >> n >> k;
priority_queue<PLL, vector<PLL>, greater<PLL>> heap;
for (int i = 0; i < n; i ++ ) {
LL x;
cin >> x;
heap.push({x, 0});
}
/* 伞兵了,是余数,还需要补充 (k-1)-cnt 个...
LL cnt = (n - 1) % (k - 1);
cnt = cnt == 0 ? cnt : (k - 1) - cnt;
while (cnt -- ) heap.push({0, 0});
*/
while ((heap.size() - 1) % (k - 1)) heap.push({0, 0});
LL res = 0;
while (heap.size() > 1) {
LL sum = 0, depth = 0;
for (int i = 0; i < k; i ++ ) {
auto t = heap.top(); heap.pop();
sum += t.first, depth = max(depth, t.second);
}
heap.push({sum, depth + 1});
res += sum;
}
cout << res << '\\n' << heap.top().second << endl;
return 0;
}
#include <bits/stdc++.h>
using namespace std;
int main() {
int T = 1;
cin >> T;
while(T--) {
int n, M;
cin >> n >> M;
vector<int> a(n + 2), light(n + 2), dark(n + 2);
a[0] = 0, a[n + 1] = M;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1 ; i <= n + 1; i++) {
light[i] += light[i - 1];
dark[i] += dark[i - 1];
if(i & 1) light[i] += a[i] - a[i - 1];
else dark[i] += a[i] - a[i - 1];
}
int ret = light[n + 1]; // 不加入新操作
for(int i = 0; i <= n; i++) {
ret = max(ret, light[i] - light[0] + dark[n + 1] - dark[i + 1] + a[i + 1] - a[i] - 1);
}
cout << ret << endl;
}
return 0;
}
以上是关于[贪心] aw3774. 亮灯时长(思维+后缀和+代码细节+CF1000B)的主要内容,如果未能解决你的问题,请参考以下文章
[模拟] aw3664. 数组补全(模拟+贪心+中位数+思维)
CodeForces 1000B Light It Up(贪心思维)