1 条题解
-
0
思路
观察:
- 能量核心被分成若干个「段」,每段由连续的非零元素组成(段与段之间由零隔开);
- 每个包含核心的连续段必须至少手动激活一个核心,之后连锁反应会把该段内所有核心全部激活;
- 因此对每一段,最优策略就是手动激活该段中消耗最少的那个核心,该段花费等于段内最小值;
- 不同段之间互不影响,总消耗 = 所有段的最小值之和。
实现:
- 边读入边处理:维护当前段的最小值
mi; - 遇到 :当前段结束,把
mi累加进总消耗,并把mi重置为「无穷大」(若此前没有非零元素则段为空,加 ); - 遇到非零元素:用
min(mi, x)更新当前段最小值; - 数组读完后还要再结算一次最后一段,避免漏掉结尾不是零的段。
边界: 全为 时没有任何段,答案为 ;
mi==inf的判断正是用来跳过空段。复杂度: 每个测试用例时间 (多组数据合计 ),额外空间 。
代码
#include<bits/stdc++.h> #define int long long #define dd double #define str string #define el cout << '\n' #define re return #define ff first #define ss second #define pll pair<int,int> #define pdd pair<dd,dd> #define all(x) x.begin(),x.end() #define pb push_back using namespace std; void go(){ int n;cin>>n; int inf = 1e18; int tot = 0, mi = inf; // tot 总消耗,mi 当前段的最小值 for(int i=1;i<=n;i++){ int x;cin>>x; if(x==0){ // 遇到 0,当前段结束:累加段内最小值;空段(mi 仍为 inf)加 0 tot += (mi==inf?0:mi); mi = inf; // 重置,开始下一段 }else{ mi = min(mi, x); // 维护当前段的最小消耗 } } // 结算最后一段(数组以非零元素结尾时不会被上面的 0 触发) tot += (mi==inf?0:mi); cout<<tot<<endl; } signed main() { ios::sync_with_stdio(false); cin.tie(nullptr);cout.tie(nullptr); int _=1; cin >>_; // 多组测试数据 while(_--){ go(); } return 0; }
- 1
信息
- ID
- 36
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者