### q838. 3. 貪心闖關
###### 2025年6月
### 題目大意
給定一個數列,每次從裡面選取最小值,如果有多個最小值,選擇所有最小值位置中最左邊的。如果在`t`以內,答案加上`t`後把這個值加到加下一個非`0`的位置,如果沒有下一個,則不必加到下一個位置。
### 解題想法
#### 1.priority_queue
每次都要找最小值位置$\Rightarrow$聯想到`priority_queue(heap)的特性`。
以`pair`作為容器,第一個放沙包數,第二個放位置。不過要先求最小,C++後面要加`greater<>`
#### 2. lazy update
不過每次下一個的值都會改變,不可能每次都從`pq(priority_queue)`刪去後再更新。這時可以使用`lazy update`的概念,也就是不直接刪除,而是新開一個陣列確認目前位置對到的值是否是有更新過的。
例如原本陣列`[1,4]`,`pq`是`{{1,0},{4,1}}`。更新完後變成`[0,5]`,這時原本`{4,1}`已經無效,但我們可以等pop出來再檢查,發現與現在不符就直接繼續。
#### 3. set&upper_bound
每次找下一個非`0`的位置,不可能使用迴圈檢查,因為時間複雜度$O(n)$。
可以開一個`set`儲存現在非`0`位置,每次使用`upper_bound`找尋下一個非`0`位置,如果是最後一個就不處理,最後在刪掉即可。時間複雜度$O(log n)$
### 複雜度
時間複雜度$O(n log n)$,不過常數偏大
空間複雜度$O(n)$
### 實作程式
:::spoiler C++ AC(0.7s, 28.8MB) code
```cpp=
#include<bits/stdc++.h>
using namespace std;
int main(){
long long int n,t,x,ans=0;cin>>n>>t;
vector<long long int> now_data(n,0);
priority_queue<pair<long long int,int>,vector<pair<long long int,int>>,greater<>> pq;
set<int> pos;
for(int i=0;i<n;i++){
cin>>x;
pq.push({x,i});
now_data[i]=x;
pos.insert(i);
}
while (pos.size()>0 and pq.size()>0) {
pair<long long int,int> data=pq.top();
pq.pop();
long long int now_cost=data.first;
int now_index=data.second;
if(now_cost>t)break;
if(now_data[now_index]!=now_cost)continue;
now_data[now_index]=0;
auto it=(pos.upper_bound(now_index));
if (it!=pos.end()){
now_data[*it]+=now_cost;
pq.push({now_data[*it],*it});
}
ans+=now_cost;
pos.erase(now_index);
}
cout<<ans;
}
```
:::
::: spoiler C++ AC(0.4s,28.9MB) code(IO優化)
```cpp=
#include<bits/stdc++.h>
using namespace std;
int main(){
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
long long int n,t,x,ans=0;cin>>n>>t;
vector<long long int> now_data(n,0);
priority_queue<pair<long long int,int>,vector<pair<long long int,int>>,greater<>> pq;
set<int> pos;
for(int i=0;i<n;i++){
cin>>x;
pq.push({x,i});
now_data[i]=x;
pos.insert(i);
}
while (pos.size()>0 and pq.size()>0) {
pair<long long int,int> data=pq.top();
pq.pop();
long long int now_cost=data.first;int now_index=data.second;
if(now_cost>t)break;
if(now_data[now_index]!=now_cost)continue;
now_data[now_index]=0;
auto it=(pos.upper_bound(now_index));
if (it!=pos.end()){
now_data[*it]+=now_cost;
pq.push({now_data[*it],*it});
}
ans+=now_cost;
pos.erase(now_index);
}
cout<<ans;
}
```
:::