题解:[NOIP 2015 普及组] 推销员

题目传送门

题意分析

\(\mathcal O\left(n^2\right)\) 做法

观察样例解释可以发现,\(x+1\) 的最优解包含 \(x\) 的最优解。

证明也很简单。在拜访 \(x+1\) 家时,一定会拜访前 \(x\) 家,这前 \(x\) 家的答案即 \(x\) 的答案,再新拜访一家即可。废话。

那么我们就可以 \(\mathcal O(n)\) 求出 \(x=1\) 的答案,然后 \(\mathcal O(n)\) 加点求出 \(x+1\) 的答案。

总时间复杂度:\(\mathcal O\left(n^2\right)\)

\(\mathcal O\left(n\log n\right)\) 做法

我们考虑优化 \(\mathcal O\left(n^2\right)\) 做法。

\(\mathcal O(n)\) 加点其实就是求每个点的贡献的最大值,因此我们考虑用一个数据结构来维护贡献。

容易想到维护一个大根堆来维护贡献。

令当前最远节点为 \(mid\),其距离即 \(s_{mid}\)

用大根堆 \(l\) 维护 \(mid\) 左边的节点,\(r\) 维护 \(mid\) 右边的节点。

则对于点 \(i\)

  • \(i<mid\)\(i\)\(l\) 中,其贡献为 \(a_i\)

  • \(i>mid\)\(i\)\(r\) 中,其贡献为 \(a_i+2(s_i-s_{mid})\)

    比较时,\(s_{mid}\) 显然是确定的,因此 \(r\) 需要维护 \(a_i+2s_i\) 的最大值。

此外,当 \(r\) 中的点加入时,最远点 \(mid\) 会更新,此时还要将满足 \(s_i\leq s_{mid}\)\(r\) 中的点 \(i\) 加入 \(l\) 中。

\(n\) 次操作,每次操作 \(\mathcal O\left(\log n\right)\)

将点从 \(r\) 中加入 \(l\) 中,最多 \(n\) 个点,时间复杂度 \(\mathcal O\left(n\log n\right)\)

总时间复杂度:\(\mathcal O\left(n\log n\right)\)

AC 代码

//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
constexpr const int N=100000;
int n;
struct node{
	int s,a;
	bool used;
}a[N+1];
priority_queue<int,vector<int> >l;
//权值,id
priority_queue<pair<int,int>,vector<pair<int,int> > >r;
int main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i].s;
	}
	for(int i=1;i<=n;i++){
		cin>>a[i].a;
	}
	int ans=-1,mid=-1;
	for(int i=1;i<=n;i++){
		int pl=2*a[i].s+a[i].a;
		if(pl>ans){
			ans=pl;
			mid=i;
		}
	}
	a[mid].used=true;
	cout<<ans<<'\n';
	for(int i=1;i<mid;i++){
		l.push(a[i].a);
	} 
	for(int i=mid+1;i<=n;i++){
		r.push({a[i].a+2*a[i].s,i});
	}
	int midFirst=mid;
	for(int x=2;x<=n;x++){		
		while(r.size()&&a[r.top().second].s<=a[mid].s){
			l.push(a[r.top().second].a);
			r.pop();
		}
		if(l.size()&&r.size()){
			if(l.top()>r.top().first-2*a[mid].s){
				ans+=l.top();
				l.pop();
			}else{
				ans+=r.top().first-2*a[mid].s;
				mid=r.top().second;
				r.pop();
			}
		}else if(l.size()){
			ans+=l.top();
			l.pop();
		}else{
			ans+=r.top().first-2*a[mid].s;
			mid=r.top().second;
			r.pop();
		}
		cout<<ans<<'\n'; 
	} 
	
	/*fclose(stdin);
	fclose(stdout);*/
	return 0; 
} 
posted @ 2025-07-21 21:51  TH911  阅读(8)  评论(0)    收藏  举报