zoukankan      html  css  js  c++  java
  • 洛谷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
    ",suma,sumb);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    第四章 利用函数实现指定的功能
    5-7 点到原点的距离(多态)
    5-2 宠物的生长(多态)
    5-7 学生cpp成绩统计
    5-6 学生CPP成绩计算
    php将远程图片下载保存到本地
    vs2010 调试快捷键
    vs2010 快捷键大全
    [C#] 使用Application.AddMessageFilter当做Form的热键
    C# 收发和处理自定义的WINDOWS消息
  • 原文地址:https://www.cnblogs.com/Forever-666/p/11210604.html
Copyright © 2011-2022 走看看