其他分享
首页 > 其他分享> > [NOIP2015 普及组] 推销员题解

[NOIP2015 普及组] 推销员题解

作者:互联网

题型考察

此题的数据范围提示时间复杂度 为 \(\text{O(n)}\) 或 \(\text{O(nlogn)}\) 考虑贪心。

思路

很明显对于每个 \(X\),都要 \(\text{O(1)}\) 或 \(\text{O(logn)}\) 进行回答,有两种思路,预处理和问题递进,这里使用问题递进。
所谓问题递进就是在 \(X\) 从小到大经过较少的调整得到新问题的解。在这里对于 \(X=1\) ,显然问题的答案为:

\[\max_{1 \leq i \leq n}{s_i \times 2 + a_i} \]

记录当前取得最大值的住户为 \(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