【题解】洛谷P1081 开车旅行(倍增)

这道题目的难度估计是noip之壁了吧。。。

70分的模拟做法之前已经讲过了,现在来说说100分的倍增做法。

首先,读入海拔后,我们可以预处理出从任意一个城市出发, 小A与小B能到达的下一个城市。思路就这么短,但代码非常繁琐,我感觉这部分甚至比倍增还麻烦。我们需要先将城市编号与海拔存在结构体内,对结构体按海拔高低进行排序,然后从1号城市到n号城市寻找其左右相邻的两个城市(还要这样离得最近),判断出来后通过链表记录前驱后继来删除该节点,将每一种情况都考虑到,还要注意是否越界。。。我个人一开始想的太简单,后来一点一点改,不断尝试输出数据直到正确为止,花了我两个半小时。。。这里讲讲能让这部分简单的方法吧。可以将数组的0位和n+1、n+2位设成非常大的数,然后对处在1位置上的数进行特判,这样一来我们的边界情况只用考虑左边界,而且可以解决。我的链表是按照位置存的,排完序后我还开了一个to数组记录某个城市排序后所在的位置。这样在枚举城市时可以直接用to[i]代表当前城市所在位置,而链表又是按照位置存的,相对来说比较方便。处理完这个问题,我们就需要用倍增解决剩下的问题了。我们定义go[i][j]代表从第i号城市出发,经过2^j轮所到达的城市,注意这里的轮是指小A小B都走过了,而且一定是小A先走的。定义A[i][j]代表小A从第i号城市出发,经过2^j轮所经过的路程,B[i][j]代表小A从第i号城市出发后小B走,经过2^j轮所经过的路程。这里的i一定是在一轮内的i,举个例子,go[i][0],i为1,1号城市到2号城市海拔差为6,2号到3号为5,那么A[i][0]=6,B[i][0]=5。明白这一点后,我们需要对倍增数组初始化,go[i][0]就是tb[ta[i]],也就是A走到某个城市后B在这个城市的基础上再走所到达的城市。A[i][0]就是小A从i出发到达城市的海拔减去一开始所在城市海拔的绝对值,B[i][0]就是在某一轮内从i号城市出发,最后到达的城市的海拔减去小A到达的城市的海拔的绝对值(为什么是这样,上面有例子了)。然后我们可以从1-20更新倍增数组,思路和一般的倍增差不多。得到了以上信息,我们就可以回答题目问的问题了。第一问是对于给定的最大路程,求从哪个城市出发小A/小B的值最小。那么我们写一个函数f(start,x),代表从start城市出发,最大路程是x。首先db=0的话答案是正无穷,不用考虑(其实也有可能都是正无穷 不过数据里没有这种情况)设da、db分别代表小A走的路程与小B走的路程然后我们从19到0枚举倍增数组,如果go[start][i]不是0(没有走超了地图)并且da+db+A[start][i]+B[start][i]在最大限度内,就更新da、db与出发点start。注意这是一整轮的情况,有可能走完一整轮后下一轮小B不能再走但小A能走,所以在倍增数组外判断一下如果小A还能走且在限度内就更新da。这样回到第一问,我们枚举出发点、不断更新最小值,最后就能得到从哪个城市出发AB比值最小了。对于第二问,我们只需要将读入的城市与限度放到函数里,输出da、db即可。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#define ll long long
using namespace std;
const int maxn=100010;
int ta[maxn],tb[maxn];
int to[maxn];
int h[maxn];
int go[maxn][25],A[maxn][25],B[maxn][25];
int n,m,da,db;
double minn=1e9;
ll x0;
struct city
{
	ll h;
	int id;
	int pre;
	int nnext;
}a[maxn];
bool cmp(const city &a,const city &b)
{
	return a.h<b.h;
}
void pd(int start,ll x)
{
	da=0,db=0;
	for(int i=19;i>=0;i--)
	{
		if(go[start][i]!=0&&(ll)(da+db+A[start][i]+B[start][i])<=x)
		{
			da+=A[start][i];
			db+=B[start][i];
			start=go[start][i];
		}
	}
	if(ta[start]!=0&&(ll)(da+db+A[start][0])<=x)
	{
		da+=A[start][0];
	}
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&h[i]);
		a[i].h=h[i];
		a[i].id=i;
	}
	sort(a+1,a+n+1,cmp);
	a[0].h=a[n+1].h=a[n+2].h=1e10;
	for(int i=1;i<=n;i++)
	{
		a[i].pre=i-1;
		a[i].nnext=i+1;
		to[a[i].id]=i;
	}

	for(int i=1;i<=n;i++)
	{
		int m1=0,m2=0;
		if(to[i]==1)
		{
			m1=a[a[to[i]].nnext].id;
			m2=a[a[a[to[i]].nnext].nnext].id;
		}
		else 
		{
			if(abs(a[a[to[i]].nnext].h-a[to[i]].h)>abs(a[a[to[i]].pre].h-a[to[i]].h))
			{
				m1=a[a[to[i]].pre].id;
				if(abs(a[a[to[i]].nnext].h-a[to[i]].h)>abs(a[a[a[to[i]].pre].pre].h-a[to[i]].h))
				{
					m2=a[a[a[to[i]].pre].pre].id;
				}
				if(abs(a[a[to[i]].nnext].h-a[to[i]].h)<abs(a[a[a[to[i]].pre].pre].h-a[to[i]].h))
				{
					m2=a[a[to[i]].nnext].id;
				}
				if(abs(a[a[to[i]].nnext].h-a[to[i]].h)==abs(a[a[a[to[i]].pre].pre].h-a[to[i]].h))
				{
					m2=a[a[a[to[i]].pre].pre].id;
				}
			}
			if(abs(a[a[to[i]].nnext].h-a[to[i]].h)<abs(a[a[to[i]].pre].h-a[to[i]].h))
			{
				m1=a[a[to[i]].nnext].id;
				if(abs(a[a[a[to[i]].nnext].nnext].h-a[to[i]].h)>abs(a[a[to[i]].pre].h-a[to[i]].h))
				{
					m2=a[a[to[i]].pre].id;
				}
				if(abs(a[a[a[to[i]].nnext].nnext].h-a[to[i]].h)<abs(a[a[to[i]].pre].h-a[to[i]].h))
				{
					m2=a[a[a[to[i]].nnext].nnext].id;
				}
				if(abs(a[a[a[to[i]].nnext].nnext].h-a[to[i]].h)==abs(a[a[to[i]].pre].h-a[to[i]].h))
				{
					m2=a[a[to[i]].pre].id;
				}
			}
			if(abs(a[a[to[i]].nnext].h-a[to[i]].h)==abs(a[a[to[i]].pre].h-a[to[i]].h))
			{
				m1=a[a[to[i]].pre].id;
				m2=a[a[to[i]].nnext].id;
			}
		}
		a[a[to[i]].pre].nnext=a[to[i]].nnext;
		a[a[to[i]].nnext].pre=a[to[i]].pre;
		ta[i]=m2;
		tb[i]=m1;
	}
	

	for(int i=1;i<=n;i++)
	{
		go[i][0]=tb[ta[i]];
		A[i][0]=abs(h[ta[i]]-h[i]);
		B[i][0]=abs(h[go[i][0]]-h[ta[i]]);
	}

	for(int i=1;i<=20;i++)
	{
		for(int j=1;j<=n;j++)
		{
			go[j][i]=go[go[j][i-1]][i-1];
			A[j][i]=A[j][i-1]+A[go[j][i-1]][i-1];
			B[j][i]=B[j][i-1]+B[go[j][i-1]][i-1];
		}
	}
	scanf("%lld %d",&x0,&m);
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		pd(i,x0);
	//	cout<<da<<' '<<db<<endl;
		if(db!=0&&1.0*da/db<minn)
		{
			minn=1.0*da/db;
			ans=i;
		}
	}
	printf("%d\n",ans);

	for(int i=1;i<=m;i++)
	{
		int s;
		ll x;
		scanf("%d %lld",&s,&x);
		pd(s,x);
		printf("%d %d\n",da,db);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Rem_Inory/article/details/81570364