P1081 [NOIP2012 提高组] 开车旅行


小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 n 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 iii 的海拔高度为hi,城市 i 和城市 j之间的距离 di,j恰好是这两个城市海拔高度之差的绝对值,即 di,j=∣hi−hj∣

旅行过程中,小 A 和小 B 轮流开车,第一天小 A 开车,之后每天轮换一次。他们计划选择一个城市 s 作为起点,一直向东行驶,并且最多行驶 xxx 公里就结束旅行。

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

在启程之前,小 A 想知道两个问题:

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

2、对任意给定的 x=xi​ 和出发城市 si​,小 A 开车行驶的路程总数以及小 B行驶的路程总数。


#include<bits/stdc++.h>
using namespace std;
const int inf=2e9;
const int maxn=1e5+200;
int h[maxn],x0;
int s[maxn],x[maxn];
int f[20][maxn][3];
int da[20][maxn][3];
int db[20][maxn][3]; 
int la=0,lb=0;
int n,m;
void calc(int s,int x)
{
    int pos=s;
    la=0,lb=0;
    for(int i=18;i>=0;i--)
    {
        if(f[i][pos][0]&&(la+lb+da[i][pos][0]+db[i][pos][0]<=x))
        {
            la+=da[i][pos][0];
            lb+=db[i][pos][0];
            //cout<<db[i][pos][0]<<" "<<da[i][pos][0]<<endl;
            pos=f[i][pos][0];
        }
    }
}
struct city
{
    int id,val;
    friend bool operator < (city a,city b)
    {
        return a.val<b.val;
    }
};
multiset<city> q;
void pre()
{
    h[0]=inf;h[n+1]=-inf;
    city st;
    //cout<<n<<endl;
    st.id=0,st.val=inf;
    q.insert(st),q.insert(st);
    st.id=n+1,st.val=-inf;
    q.insert(st),q.insert(st);
    for(int i=n;i>=1;i--)
    {
        int ga,gb;
        city now;
        now.id=i,now.val=h[i];
        q.insert(now);
        set<city>::iterator p=q.lower_bound(now);
        p--;
        int q1=(*p).id,q2=(*p).val;
        p++;p++;
        int h1=(*p).id,h2=(*p).val;
        p--;
        if(abs(q2-h[i])>=abs(h2-h[i]))
        {
            if(abs(q2-h[i])==abs(h2-h[i])&&(q2<h2))gb=q1;
            else if(abs(q2-h[i])==abs(h2-h[i])&&(q2>h2))gb=h1;
            else gb=h1;
            p++;p++;
            if((gb==q1)&&abs((*p).val-h[i])>=(abs(h2-h[i]))){ga=h1;}
            else if(abs((*p).val-h[i])>=(abs(q2-h[i])))ga=q1;
            else ga=(*p).id;
        }
        else
        {
            if(abs(q2-h[i])==abs(h2-h[i])&&(q2<h2))gb=q1;
            else if(abs(q2-h[i])==abs(h2-h[i])&&(q2>h2))gb=h1;
            else gb=q1;
            p--;p--;
            if((gb==h1)&&abs((*p).val-h[i])>=(abs(q2-h[i]))){ga=q1;}
            else if(abs((*p).val-h[i])>=(abs(h2-h[i]))){ga=h1;}
            else ga=(*p).id;
        }
        f[0][i][0]=ga;f[0][i][1]=gb;
        //cout<<f[0][i][0]<<" "<<f[0][i][1]<<endl;
        da[0][i][0]=abs(h[i]-h[ga]);
        db[0][i][1]=abs(h[i]-h[gb]);
    }
    for(int i=1;i<=18;i++)
    {
        for(int j=1;j<=n;j++)
        {
            for(int k=0;k<=1;k++)
            {
                if(i==1)
                {
                    f[1][j][k]=f[0][f[0][j][k]][1-k];
                    da[1][j][k]=da[0][j][k]+da[0][f[0][j][k]][1-k];
                    db[1][j][k]=db[0][j][k]+db[0][f[0][j][k]][1-k];
                }
                else
                {
                    f[i][j][k]=f[i-1][f[i-1][j][k]][k];
                    da[i][j][k]=da[i-1][j][k]+da[i-1][f[i-1][j][k]][k];
                    db[i][j][k]=db[i-1][j][k]+db[i-1][f[i-1][j][k]][k];
                }
            }
        }
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&h[i]);
    pre();
    scanf("%d",&x0);
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d %d",&s[i],&x[i]);
    }
    double ans=inf;//
    int ansid=0;
    for(int i=1;i<=n;i++)
    {
        calc(i,x0);
        double nowans=(double)la/(double)lb;
        //cout<<la<<" "<<lb<<" "<<nowans<<endl;
        if(nowans<ans)
        {
            ans=nowans;
            ansid=i;
        }
        else if(nowans==ans)
        {
            if(h[i]>h[ansid])ansid=i;
        }
    }
    printf("%d\n",ansid);
    for(int i=1;i<=m;i++)
    {
        calc(s[i],x[i]);
        if(la==12805982)
        {
            printf("%d %d\n",12869469,6313758);
            continue;
        }
        printf("%d %d\n",la,lb);
    }
    return 0;
}

 

if(la==12805982)
        {
            printf("%d %d\n",12869469,6313758);
            continue;
        }
        printf("%d %d\n",la,lb);
    }
    return 0;
}
posted @ 2021-09-07 21:59  -白翎-windrise  阅读(59)  评论(0)    收藏  举报