[NOIP2015 普及组] 推销员题解
作者:互联网
题型考察
此题的数据范围提示时间复杂度 为 \(\text{O(n)}\) 或 \(\text{O(nlogn)}\) 考虑贪心。
思路
很明显对于每个 \(X\),都要 \(\text{O(1)}\) 或 \(\text{O(logn)}\) 进行回答,有两种思路,预处理和问题递进,这里使用问题递进。
所谓问题递进就是在 \(X\) 从小到大经过较少的调整得到新问题的解。在这里对于 \(X=1\) ,显然问题的答案为:
记录当前取得最大值的住户为 \(bpos\)。
考虑到 \(X=2\)。可以很容易的证明,答案一定是基于 \(X=1\) 的答案所扩展的,考虑多选择的住户为 \(i\)。
当 \(i<bpos\)时,答案在原基础上增加 \(a_i\)。
当 \(i>bpos\)时,答案在原基础上增加 \(2 \times (s_i-s_{bpos})+a_i\)。
如果要求答案最大,则
当 \(i<bpos\)时,使得 \(a_i\) 最大,记答案为 \(ansL\)。
当 \(i>bpos\)时,使得 \(2 \times s_i+a_i\) 最大,记答案为 \(ansR\)。
利用优先队列维护即可。
当 \(ansL \leq ansR\) 时,答案增加 \(ansR\),可以发现,为了保持最优性,新的 \(bpos\) 为使得 \(2 \times s_i+a_i\) 最大的住户,然后同时调整左右边的优先队列。
当 \(ansL > ansR\) 时,答案增加 \(ansL\),可以发现,不需要调整 \(bpos\),然后调整左边的优先队列。
上述过程考场上不用严格证明,手推样例即可领悟。
细节方面判断要特殊处理队空的情况。
代码实现
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n,ans,bpos,ansL;
int s[N],a[N];
struct node {
int pos,val;
friend bool operator < (node x,node y) {
return x.val<y.val;
}
}qwq,ansR;
priority_queue<int>q1;
priority_queue<node>q2;
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++) cin>>s[i];
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) {
qwq.pos=i;
qwq.val=2*s[i]+a[i];
q2.push(qwq);
}
for(int i=1;i<=n;i++) {
ansL=ansR.val=0;
if(!q1.empty()) ansL=q1.top();
while(!q2.empty()&&q2.top().pos<=bpos) q2.pop();
if(!q2.empty()) ansR=q2.top();
if(ansL<ansR.val-2*s[bpos]) {
ans+=ansR.val-2*s[bpos];
for(int j=bpos+1;j<=ansR.pos-1;j++) q1.push(a[j]);
bpos=ansR.pos;
q2.pop();
}
else {
ans+=ansL;
q1.pop();
}
cout<<ans<<endl;
}
return 0;
}
标签:NOIP2015,int,题解,ansR,times,bpos,推销员,答案,text 来源: https://www.cnblogs.com/2021hych/p/16508138.html