题解:[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;
}

浙公网安备 33010602011771号