倍增没有学,不过我们可以通过模拟和dfs得到70分的部分分。
手写dis函数求两个城市距离=海拔差的绝对值。设一个km[i][2]的二维数组,来记录离i个城市距离最近和第二近的城市,要注意题目里有许多细节。例如距离相同时判断海拔低的城市更近。设m2 m1为0代表离i次近和最近的城市,循环城市i,再循环j(i+1 到 n),如果满足上述条件,就用j更新m1,m1更新m2。当然存在j不是最近但能更新次近的情况,用if处理即可。输入x0。第一问让我们求总路程不超过x0时从哪个城市出发a和b开车距离比值最小。可以通过dfs传四个参数模拟,s表示开始城市的编号,x表示该小a还是小b开车了(在之前的km数组里存过),da、db分别表示小A小B开车走过的距离。如果当前城市的前面没有合法的城市了或者da、db、s和to之间距离之和大于x0就停止。否则传入参数等于2时,代表小A开车,da+=dis(s,to),从to开始dfs,传入参数转化为另一种。利用这个dfs我们第一问可以枚举城市求出其da、db值,如果db==0并且比值为-1(代表正无穷),那么就该比较两者的海拔。若当前城市海拔高于ans海拔,更新ans。若db不为0,如果比值为-1就更新,如果比值不为-1的话,在da/db(double类型)<比值或等于比值、海拔更高的情况下更新ans,可以求出第一问。对于第二问,读入处罚城市和最大限度后,利用dfs函数求出da db 输出即可
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;
int n,m;
int h[100100];
int q,x0;
int km[100100][3];
int dis(int x,int y)
{
if(x==0||y==0) return (2e9)+1;
return abs(h[x]-h[y]);
}
void dfs(int s,int x,int &da,int &db)
{
int to=km[s][x];
if(to==0) return ;
int d=dis(s,to);
if(da+db+d>x0) return;
if(x==1)
{
db+=d;
dfs(to,2,da,db);
}
if(x==2)
{
da+=d;
dfs(to,1,da,db);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&h[i]);
}
for(int i=1;i<=n;i++)
{
int m1=0,m2=0;
for(int j=i+1;j<=n;j++)
{
if(dis(m1,i)>dis(j,i)||(dis(m1,i)==dis(j,i)&&h[j]<h[m1]))
{
m2=m1;
m1=j;
}
else
{
if(dis(m2,i)>dis(j,i)||(dis(m2,i)==dis(j,i)&&h[j]<h[m2]))
{
m2=j;
}
}
}
km[i][1]=m1;
km[i][2]=m2;
}
scanf("%d",&x0);
int ans=0;
double ra=-1; //比值无穷大
for(int i=1;i<=n;i++)
{
int da=0,db=0;
dfs(i,2,da,db);
if(db==0)
{
if(ra==-1&&h[i]>h[ans])
{
ans=i;
}
}
if(db!=0)
{
if(ra==-1||(1.0*da/db<ra||(1.0*da/db==ra&&h[i]>h[ans])))
{
ans=i;
ra=1.0*da/db;
}
}
}
cout<<ans<<endl;
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int si;
scanf("%d%d",&si,&x0);
int da=0,db=0;
dfs(si,2,da,db);
printf("%d %d\n",da,db);
}
//fclose(stdin);
//fclose(stdout);
return 0;
}