洛谷P1081——开车旅行

传送门:QAQQAQ

题意注意点:

1.是从前往后走,不能回头

2.小A小B轮流开,先小A开,而小A是到第二近的点(这点调试的时候查了好久)

3.若绝对值差相同海拔低的更近,而第一个询问若比值相同是海拔高的更优

思路:我们先预处理出离i点最近和次近点的编号,没有就是-1(链表可以达到O(n),但是用STL O(nlog(n)) 绰绰有余,代码量还小)

然后用倍增预处理出从i号点走2^j轮A走的路程,B走的路程,和走完这些轮最终停下的点(定义AB各走一次为一轮)

注意可能走半轮,即最后一下A走B不走。

写题过程:

大佬MYY告诉我不要心急,先打70分暴力,然后打了2个小时暴力(STL真的好难查啊QAQ) 打完暴力以后告诉我主程序要全部删掉重写。。。。。

看到直接旁边的HCY没打暴力直接正解AC,心态崩了。。。

然后就在没有特判掉走不到的情况和AB顺序一半写正,一般写反上调了好久,不过最终做出来还是蛮有成就感的(感觉自己很弱啊。。

代码:

#include<bits/stdc++.h>
#define m_k make_pair
#define ll long long
using namespace std;
const ll N=102000;
const ll inf=(ll)5e18;

ll f[N][2],n,m,a[N],x0;
//0:closest 1:second closest
ll dp[N][20][2],Bits[20],p[N][20];
//0:disB 1:disA p:finalpos AB为一轮,走2^t轮 

ll _abs(ll x)
{
    if(x<0) return -x;
    else return x;
}

set<pair<ll,ll> > st;
vector<pair<ll,ll> > tmp;
void init()
{
    memset(f,-1,sizeof(f));
    st.insert(m_k(a[n],n));
    st.insert(m_k(a[n-1],n-1));
    f[n-1][0]=n;
    for(ll i=n-2;i>=1;i--)
    {
        ll bl=0;
        tmp.clear();
        set<pair<ll,ll> > :: iterator it;
        it=st.lower_bound(m_k(a[i],i));
        if(it!=st.end()) tmp.push_back(*it),it++,bl++;
        if(it!=st.end()) tmp.push_back(*it);
        if(bl) it--;
        it--;
        set<pair<ll,ll> > :: iterator be;
        be=st.begin(); be--;
        if(it!=be) tmp.push_back(*it),it--;
        if(it!=be) tmp.push_back(*it);
        ll ans1=inf,ans2=inf;
        for(ll j=0;j<(ll)tmp.size();j++)
        {
            if(ans1>_abs(a[i]-tmp[j].first)||(ans1==_abs(a[i]-tmp[j].first)&&a[f[i][0]]>tmp[j].first))
            {
                f[i][1]=f[i][0]; ans2=ans1;
                f[i][0]=tmp[j].second; ans1=_abs(a[i]-tmp[j].first);
            }
            else if(ans2>_abs(a[i]-tmp[j].first)||(ans2==_abs(a[i]-tmp[j].first)&&a[f[i][1]]>tmp[j].first))
            {
                f[i][1]=tmp[j].second; ans2=_abs(a[i]-tmp[j].first);
            }
        }
        st.insert(m_k(a[i],i));
    }
}

void ready()
{
    memset(p,-1,sizeof(p));
    memset(dp,-1,sizeof(dp));
    for(ll i=1;i<=n;i++)
    {
        ll pos=f[i][1]; if(pos==-1) continue;
        dp[i][0][1]=_abs(a[pos]-a[i]);
        if(f[pos][0]==-1) continue; 
        dp[i][0][0]=_abs(a[pos]-a[f[pos][0]]);
        p[i][0]=f[pos][0];
    }
    for(ll j=1;j<20;j++)
    {
        for(ll i=1;i<=n;i++)
        {
            for(ll k=0;k<=1;k++)
                if(dp[i][j-1][k]!=-1&&dp[p[i][j-1]][j-1][k]!=-1) dp[i][j][k]=dp[i][j-1][k]+dp[p[i][j-1]][j-1][k];
            if(p[i][j-1]!=-1) p[i][j]=p[p[i][j-1]][j-1];
            
        }
    }
}

ll suma,sumb;
double calc(ll x,ll y)
{
    if(y==0) return inf*1.0;
    return(x*1.0)/(y*1.0);
}

int main()
{
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++) scanf("%lld",&a[i]);
    init();
    ready();
    scanf("%lld",&x0);
    double ans=inf*1.0;
    ll now=0;
    a[0]=-inf;
    for(int i=1;i<=n;i++)
    {
        ll suma=0,sumb=0,pos=i;
        for(int j=19;j>=0;j--)
        {
            if(dp[pos][j][0]==-1||dp[pos][j][1]==-1||p[pos][j]==-1) continue;
            if(dp[pos][j][0]+dp[pos][j][1]+suma+sumb>x0) continue;
            suma+=dp[pos][j][1];
            sumb+=dp[pos][j][0];
            pos=p[pos][j];
        }
        if(dp[pos][0][1]+suma+sumb<=x0&&dp[pos][0][1]!=-1) suma+=dp[pos][0][1];
        if(ans>calc(suma,sumb)||(ans==calc(suma,sumb)&&a[i]>a[now]))
        {
            now=i;
            ans=calc(suma,sumb);
        }
    }
    cout<<now<<endl; ll pos;
    scanf("%lld",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%lld%lld",&pos,&x0);
        suma=0; sumb=0;
        for(int j=19;j>=0;j--)
        {
            if(dp[pos][j][0]==-1||dp[pos][j][1]==-1||p[pos][j]==-1) continue;
            if(dp[pos][j][0]+dp[pos][j][1]+suma+sumb>x0) continue;
            suma+=dp[pos][j][1];
            sumb+=dp[pos][j][0];
            pos=p[pos][j];
        }
        if(dp[pos][0][1]+suma+sumb<=x0&&dp[pos][0][1]!=-1) suma+=dp[pos][0][1];
        printf("%lld %lld\n",suma,sumb);
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/Forever-666/p/11210604.html