洛谷 P2672 【推销员】

  • 如果当前点在最大距离点左边,只加上推销疲劳值

  • 如果当前点在最大距离点右边,还要在加上两倍距离差,并更新最大距离点

首先很容易想到一个贪心:找在最大距离左边最优的点与右边最优的点进行比较(写成程序就是两个if),取最优。

并且还要判断该点没有去过。

最后如果取了右边的点要更新最大距离点。于是有了这份程序:

#include<bits/stdc++.h>
using namespace std;
int n;
struct node{
	int dis;//距离
	int num;//推销疲劳值
}peo[100007];
bool vis[100007];//记录有没有去过
int maxnum;//最大距离点
int ans;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++)	
		cin>>peo[i].dis;
	for(int i=1;i<=n;i++)
		cin>>peo[i].num;
	for(int i=1;i<=n;i++){
		int maxn=0,maxi=0,k=0;
        	//总的最优情况,此时编号,两种情况的最优
		for(int j=1;j<=n;j++){
			if(!vis[j]){
				if(j<maxnum){
					k=max(k,peo[j].num);//最大距离点左边
				}
				else {
					k=max(k,peo[j].num+(peo[j].dis-peo[maxnum].dis)*2);//最大距离点右边
				}
				if(k>maxn){//更新此时最优点
					maxn=k;
					maxi=j;
				}
			}
		}
		maxnum=max(maxnum,maxi);//更新最大距离点
		vis[maxi]=true;
		ans+=k;
		cout<<ans<<endl;//每次都要输出
	}
	return 0;
}

然后能得到60分(加上快读和加ios的cout也没用)

其实已经很好了对我这个蒟蒻来说

然后就是针对剩余4个点的优化了。需要用到优先队列(我们教练告诉我的),后来看别的题解发现还可用反贪,但是我不会

定义优先队列ql,qr。ql存最大距离点左边的,qr存最大距离点右边的(只是存的时候这么存)

每次都取最大值,然后出队。在两个点中取最优,如果去qr的点,要更新最大距离点。同时判断有没有去过,若去过,也舍弃。注意:若qr的点跑到了最大距离点左边,那么这个点应该舍弃,但若ql的点跑到了最大距离点右边,不应舍弃,因为它仍有机会跑到最大距离点左边(有可能后来更新了最大距离点)。

当是第一次走的时候特判,必定走qr的点(这样才能有一个最大距离点)

#include<bits/stdc++.h>
using namespace std;
int n;
int maxdis;//最大距离点的距离
struct node{
	int dis;//ql里是推销值,qr里还要加上两倍距离
	int num;//编号
	bool operator < (const node &x) const{
		return dis<x.dis;//重载运算符,没有为什么,我也是学的别的题解里的
	}
};
int ans;
int dis[100007];//每个点的距离
int num[100007];//每个点的推销疲劳值
bool vis[100007];//同上
priority_queue<node,vector<node>,less<node> > qr,ql;//命名是套路
int main(){
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>dis[i];
	for(int i=1;i<=n;i++){
		cin>>num[i];
		node k;
		k.num=i;
		k.dis=num[i];
		ql.push(k);
		k.dis=num[i]+2*dis[i];
		qr.push(k);
		//每个节点分别入两队
	}
	vis[qr.top().num]=true;
	ans=qr.top().dis;
	cout<<ans<<endl;
	//第一个点肯定是离起点最远的那个(推销疲劳值已经加进去了)
	maxdis=dis[qr.top().num];//存下最远距离
	if(ql.top().num==qr.top().num)ql.pop();//如果该点在两个队列中都出现了,都要出队
	qr.pop();
	for(int i=2;i<=n;i++){
		node maxl=ql.top(),maxr=qr.top();
		if(vis[maxl.num]){ql.pop();i--;continue;}//队首已经去过了,舍去
		if(vis[maxr.num]){qr.pop();i--;continue;}//同上
		//记得i要--,不然相当于取了一个点,答案却没有加上
		if((maxl.dis>=(maxr.dis-2*maxdis))||((maxr.dis-num[maxr.num])<2*maxdis)){
			//这里是取两个中的最优点,有没有=均可       此处是取qr的距离    qr的点得在最大距离点右边
			ans+=maxl.dis;
			ql.pop();
		}
		else {
			ans+=maxr.dis-2*maxdis;
			maxdis=dis[maxr.num];//更新最大距离点
			qr.pop();
		}
		cout<<ans<<endl;//每次输出答案
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值