记城市 \(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
From: https://www.cnblogs.com/zhouzizhe/p/16642697.html