ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P1081 [NOIP2012 提高组] 开车旅行

2022-08-31 13:02:58  阅读:142  来源: 互联网

标签:p2 旅行 le NOIP2012 ll p1 nex P1081 ct


记城市 \(i\) 的海拔高度为\(h_i\), \(i\) 和 \(j\) 之间的距离 \(d_{i,j}=|h_i-h_j|\)。

旅行过程中,两人轮流开车,第一天 \(A\) 开车,之后每天轮换一次。选择一个城市 \(s\) 作为起点,向编号大的一方行驶,并且最多行驶 \(x\) 公里就结束旅行。

\(B\) 总是沿着前进方向选择一个最近的城市作为目的地,而 \(A\) 总是沿着前进方向选择第二近的城市作为目的地(如果当前城市到两个城市的距离相同,则认为离海拔低的那个城市更近)。如果其中任何一人无法按照自己的原则选择目的城市,或者到达目的地会使行驶的总距离超出 \(x\) 公里,他们就会结束旅行。

1、 对于一个给定的 \(x=x_0\),从哪一个城市出发, \(\frac{A}{B}\) 最小(如果 \(B\) 的行驶路程为 \(0\),此时的比值可视为无穷大,且两个无穷大视为相等)。如果从多个城市出发,\(A\) 开车行驶的路程总数与 \(B\) 行驶的路程总数的比值都最小,则输出海拔最高的那个城市。

2、对任意给定的 \(x=x_i\) 和出发城市 \(s_i\) , \(A\) 开车行驶的路程总数以及 \(B\) 行驶的路程总数。

\(1\le n,m \le 10^5\),\(-10^9 \le h_i≤10^9\),\(1 \le s_i \le n\),\(0 \le x_i \le 10^9\) , \(h_i\) 互不相同。


用 \(na[i],nb[i]\) 表示在 \(i\) 位置上下一步 \(A\) 和 \(B\) 的选择,可以倒序枚举,每次找到在 \(i\) 位置之前、之后的2个位置,就可以通过比较绝对值得到答案,这里用 multiset 来实现。

用 \(f[i][j]\) 表示 \(A,B\) 两人从 \(j\) 开始,每个人都开了 \(2^i\) 次之后到达的地方, \(na[i][j],nb[i][j]\) 表示 \(A,B\) 在 \(j\) 开始,开了 \(2^i\) 次后的总路程。那么每次询问从大到小跳倍增,若大于等于 \(x\) ,则更新,然后最后可能会剩下1轮 \(A\) 能走 \(B\) 不能走,这时候就再将 \(A\) 走一步即可。通过这样的方法可以解决2个问题。

#include<bits/stdc++.h>
using namespace std;

#define INF 1000000000000
#define ll long long
struct node
{
	ll id,h;
	friend bool operator < (node a,node b)
    {
        return a.h<b.h; 
    }
}ct[100005];

multiset <node> s;

ll n,m,na[100005],nb[100005],x0,f[20][100005],da[20][100005],db[20][100005];
ll la,lb,s0,ansa,ansb;

void solve(ll S,ll X)
{
	la=0,lb=0;
	for(int j=16;j>=0;--j)
	{
		if(f[j][S] && da[j][S]+db[j][S]<=X)
		{
			X-=da[j][S]+db[j][S];
			la+=da[j][S];
			lb+=db[j][S];
			S=f[j][S];
		}
	}
	if(na[S] && abs(ct[S].h-ct[na[S]].h)<=X)
		la+=abs(ct[S].h-ct[na[S]].h);
	return;
}

int main()
{
	//freopen("P1081.in","r",stdin);
	scanf("%lld",&n);
	for(int i=1;i<=n;++i)
	{
		scanf("%lld",&ct[i].h);
		ct[i].id=i;
	}
	ct[0].id=0;
	ct[0].h=-INF;
	ct[n+1].id=0;
	ct[n+1].h=INF;
	s.insert(ct[0]);
	s.insert(ct[0]);
	s.insert(ct[n+1]);
	s.insert(ct[n+1]);
	for(int i=n;i>=1;--i)
	{
		s.insert(ct[i]);
		set<node>::iterator p1=s.lower_bound(ct[i]);
		set<node>::iterator p2=p1;
		p1--;p2++;
		node las=(*p1),nex=(*p2);
		if(abs(las.h-ct[i].h)>abs(nex.h-ct[i].h))
		{
			nb[i]=nex.id;
			p2++;
		}
		else
		{
			nb[i]=las.id;
			p1--;
		}
		las=(*p1),nex=(*p2);
		if(abs(las.h-ct[i].h)>abs(nex.h-ct[i].h))
		{
			na[i]=nex.id;
			p2++;
		}
		else
		{
			na[i]=las.id;
			p1--;
		}
	}
	for(int i=1;i<=n;++i)
	{
		f[0][i]=nb[na[i]];
		if(na[i])
			da[0][i]=abs(ct[i].h-ct[na[i]].h);
		if(nb[na[i]])
			db[0][i]=abs(ct[na[i]].h-ct[nb[na[i]]].h);
	}
	for(int j=1;j<=16;++j)
	{
		for(int i=1;i<=n;++i)
		{
			f[j][i]=f[j-1][f[j-1][i]];
			da[j][i]=da[j-1][i]+da[j-1][f[j-1][i]];
			db[j][i]=db[j-1][i]+db[j-1][f[j-1][i]];
		}
	}
	scanf("%lld",&x0);
	ansa=1,ansb=0;
	for(int i=1;i<=n;++i)
	{
		solve(i,x0);
		if(la*ansb<lb*ansa)
		{
			ansa=la;
			ansb=lb;
			s0=i;
		}
		else if(la*ansb==lb*ansa && lb*ansa!=0 && ct[i].h>ct[s0].h)
		{
			ansa=la;
			ansb=lb;
			s0=i;
		}
	}
	printf("%lld\n",s0);
	scanf("%lld",&m);
	for(int i=1;i<=m;++i)
	{
		ll si,xi;
		scanf("%lld %lld",&si,&xi);
		solve(si,xi);
		printf("%lld %lld\n",la,lb);
	}
	return 0;
}

标签:p2,旅行,le,NOIP2012,ll,p1,nex,P1081,ct
来源: https://www.cnblogs.com/zhouzizhe/p/16642697.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有