@rebirth1120
2019-11-13T09:36:32.000000Z
字数 2777
阅读 683
解题报告
有 个城市 , 呈东西方向一字排开, 城市 的海拔为 , , 两个城市 之间的距离为 .
两人开车旅行, 从西向东行驶, 每天都能且只能沿着正方向从一个城市到达另一个城市, 第一天 开车, 之后他们每天交替开车.
的驾驶风格为每次开到离当前城市第二近的城市,
的驾驶风格为每次开到离当前城市最近的城市.
有两个问题 :
1. 给定 , 求在行驶总距离不超过 的条件下, 从哪个城市出发, 能使得 驾驶的距离 与 驾驶的距离 之比最小.
2. 给定 组 , 分别代表出发的城市和行驶的最大距离, 求 各自的驾驶距离.
其实想到倍增的话这道题就不怎么难了 (然而我是听别人说了这道题是倍增之后再去做的....)
由于从每个城市出发, 下一次到达的城市以及经过的距离是一定的, 所以可以先预处理出每座城市往后的最近城市和次近城市,
然后再预处理出 , 分别表示从点 出发, 经过 座城市后到达的城市, 的行驶距离, 的行驶距离.
最近城市和次进城市我是用 set 来处理, 然后因为 STL 运用不熟练, 还调了一段时间...
总的来说这道题还算简单, 就是预处理时有一些细节还是要注意的.
#include<bits/stdc++.h>
#define ll long long
#define itr iterator
#define lb lower_bound
using namespace std;
const int N=1e5+7;
const int L=20;
const ll inf=1e17;
int n,m,f[N][3],g[N][L+7];
ll h[N],s1[N][L+7],s2[N][L+7];
struct city{
int id;
ll h;
bool operator < (const city x) const{ return h<x.h; }
bool operator <= (const city x) const{ return h<=x.h; }
bool operator > (const city x) const{ return h>x.h; }
bool operator >= (const city x) const{ return h>=x.h; }
bool operator == (const city x) const{ return h==x.h; }
}a[N],fs[4];
set<city> S;
int now;
bool rule(city x,city y){
ll tx=abs(x.h-a[now].h),ty=abs(y.h-a[now].h);
return tx==ty ?x.h<y.h :tx<ty;
}
ll dis(int x,int y){
if(x==0||y==0) return 0;
return abs(h[x]-h[y]);
}
bool clsr(city a,city b,city x){
ll ta=abs(a.h-x.h),tb=abs(b.h-x.h);
if(ta==tb) return a.h<b.h;
else return ta<tb;
}
void pre(){
S.insert(a[n]);
// 各种丑陋的分类讨论...
for(int i=n-1;i>=1;i--){
now=i;
set<city>::itr it=S.lb(a[i]),it1,it2,it3;
if(it!=S.begin()){ it--; it1=it; it++; }
else it1=it;
if(it1!=S.begin()){ it1--; it3=it1; it1++; }
else it3=it1;
if(it!=S.end()){ it++; it2=it; it--; }
else{ it2=it=it1; }
if(it2==S.end()) it2--;
fs[1]=*it1; fs[2]=*it; fs[3]=*it2;
city t3=*it3,t2=*it2;
if(it3!=it1&&clsr(t3,t2,a[i])) fs[3]=*it3;
sort(fs+1,fs+4,rule);
if(fs[1]==fs[2]){
if(fs[1]==fs[3]) f[i][1]=0;
else f[i][1]=fs[3].id;
}
else f[i][1]=fs[2].id;
f[i][2]=fs[1].id;
S.insert(a[i]);
}
for(int i=n;i>=1;i--){
g[i][0]=f[i][1];
s1[i][0]=dis(i,f[i][1]);
g[i][1]=f[f[i][1]][2];
s1[i][1]=dis(i,f[i][1]);
s2[i][1]=dis(f[i][1],g[i][1]);
for(int k=2;k<=L;k++){
g[i][k]=g[g[i][k-1]][k-1];
s1[i][k]=s1[i][k-1]+s1[g[i][k-1]][k-1];
s2[i][k]=s2[i][k-1]+s2[g[i][k-1]][k-1];
}
}
}
void find(int s,ll x,ll &t1,ll &t2){
t1=t2=0;
for(int i=L;i>=0;i--)
if(g[s][i]&&s1[s][i]+s2[s][i]<=x){
x-=s1[s][i]+s2[s][i];
t1+=s1[s][i];
t2+=s2[s][i];
s=g[s][i];
}
}
int run(ll x0){
int ans=0; h[0]=-inf;
ll res1=0,res2=0,t1=0,t2=0;
for(int i=1;i<=n;i++){
find(i,x0,t1,t2);
if(!t2&&res2) continue;
if(res1*t2>t1*res2||(res1*t2==t1*res2&&h[i]>h[ans])){
ans=i;
res1=t1; res2=t2;
}
}
return ans;
}
int main(){
// freopen("drive1.in","r",stdin);
// freopen("drive.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++){
scanf("%lld",&h[i]);
a[i].id=i; a[i].h=h[i];
}
pre();
ll x0; scanf("%lld",&x0);
printf("%d\n",run(x0));
cin>>m; int s; ll x,t1,t2;
for(int i=1;i<=m;i++){
scanf("%d%lld",&s,&x);
find(s,x,t1,t2);
printf("%lld %lld\n",t1,t2);
}
return 0;
}