zoukankan      html  css  js  c++  java
  • 洛谷 P1086 开车旅行 【倍增+STL】

    题目:

    https://www.luogu.org/problem/show?pid=1081

    分析:

    这题第一眼给人的感觉就是要模拟,模拟两人交替开车,分别预处理出离特定城市第一近和第二近的(用set)。实际上就是这样,只不过用set和倍增优化了一下,用:

    g[i][k]表示从位置i开始,两人轮流开2^k轮车最后到达的位置;

    f[i][j][0] 表示表示从位置i开始,两人轮流开2^k轮车最后小A走过的距离;

    f[i][j][1] 表示表示从位置i开始,两人轮流开2^k轮车最后小B走过的距离;

    容易得到:

    nxt[i][1]表示离i第二近的城市编号

    nxt[i][0]表示离i第一近的城市编号

    dis[i][1]表示离i第二近的城市编号

    dis[i][0]离i第一近的城市编号

    初始化:

      g[i][0]=nxt[nxt[i][1]][0];  //从i开始两人轮流开一轮到的地方
            f[i][0][0]=dis[i][1];  //开一次b走的路径
            f[i][0][1]=dis[nxt[i][1]][0];  //开一次a走的路径

    递推:

                g[i][j]=g[g[i][j-1]][j-1];     //从第一近到第二近
                f[i][j][0]=f[i][j-1][0]+f[g[i][j-1]][j-1][0];    //A走一轮,再走一轮
                f[i][j][1]=f[i][j-1][1]+f[g[i][j-1]][j-1][1];   //B走一轮,再走一轮

    下面是参考代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <set>
    #define maxn 100000+10 
    using namespace std;
    struct point
    {
        int num,h;
        bool operator < (const point ano) const
        {
            return h<ano.h;
        }
    }city[maxn];
    set<point> S;
    set<point> :: iterator it;
    long long f[maxn][21][2];
    int nxt[maxn][2],dis[maxn][2],g[maxn][21];
    int n,x0,m;
    
    void update(point x,point y)
    {
        if(!nxt[x.num][0])
        {
            nxt[x.num][0]=y.num;
            dis[x.num][0]=abs(x.h-y.h);
        }
        else if(dis[x.num][0]>abs(x.h-y.h)||(dis[x.num][0]==abs(x.h-y.h)&&y.h<city[nxt[x.num][0]].h))
        {
            nxt[x.num][1]=nxt[x.num][0];
            dis[x.num][1]=dis[x.num][0];
            nxt[x.num][0]=y.num;
            dis[x.num][0]=abs(x.h-y.h);
        }
        else if(dis[x.num][1]>abs(x.h-y.h)||(dis[x.num][1]==abs(x.h-y.h)&&y.h<city[nxt[x.num][1]].h))
        {
            nxt[x.num][1]=y.num;
            dis[x.num][1]=abs(x.h-y.h);
        }
        else if(!nxt[x.num][1])
        {
            nxt[x.num][1]=y.num;
            dis[x.num][1]=abs(x.h-y.h);
        }
        return;
    }
    
    void query(int s,int x,long long &dista,long long &distb)
    {
        for(int i=20;i>=0;i--)
            if(f[s][i][0]+f[s][i][1]<=x&&g[s][i])//从大到小,能塞就塞 
            {
                dista+=f[s][i][0];
                distb+=f[s][i][1];
                x-=f[s][i][1]+f[s][i][0];
                s=g[s][i];
            }
        if(nxt[s][1]&&dis[s][1]<=x)
            dista+=dis[s][1];
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&city[i].h);
            city[i].num=i;
        }
        for(int i=n;i>=1;i--)
        {
            S.insert(city[i]);
            it=S.find(city[i]);
            if(it!=S.begin())
            {
                it--;
                update(city[i],*it);
                if(it!=S.begin())
                {
                    it--;
                    update(city[i],*it);
                    it++;    
                }      
                it++;
            }  
            if((++it)!=S.end())
            {
                update(city[i],*it);
                if((++it)!=S.end())
                {
                    update(city[i],*it);
                    it--;    
                }      
                it--;
            } 
        }
        for(int i=1;i<=n;i++)//初始化 
        {
            g[i][0]=nxt[nxt[i][1]][0];//从i开始两人轮流开一轮到的地方 
            f[i][0][0]=dis[i][1];//开一次b走的路径 
            f[i][0][1]=dis[nxt[i][1]][0];//开一次a走的路径 
        }
        for(int j=1;j<=20;j++)
            for(int i=1;i<=n;i++)
            {
                g[i][j]=g[g[i][j-1]][j-1];//从第一近到第二近 
                f[i][j][0]=f[i][j-1][0]+f[g[i][j-1]][j-1][0];//A走一轮,再走一轮 
                f[i][j][1]=f[i][j-1][1]+f[g[i][j-1]][j-1][1];//B走一轮,再走一轮 
            }
        scanf("%d",&x0);
        int s0=0;
        long long a=1e15,b=0;
        for(int i=1;i<=n;i++)
        {
            long long dista=0,distb=0;
            query(i,x0,dista,distb);
            if(distb&&(!s0||(dista*b<distb*a)))
            {
                s0=i;
                a=dista;
                b=distb;
            }
        }
        printf("%d
    ",s0);
        scanf("%d",&m);
        while(m--)
        {
            long long dista=0,distb=0;
            int s,x;
            scanf("%d%d",&s,&x);
            query(s,x,dista,distb);
            printf("%d %d
    ",dista,distb);
        }
        return 0;
    }
    View Code


     

     

  • 相关阅读:
    R语言学习笔记:向量化
    R语言笔记:快速入门
    再分析 返回值加引用&,const
    matlab 怎么保存plot的图 到指定文件夹
    不要在头文件中使用 using namespace std;
    散列表 (Hash table,也叫哈希表)
    重载操作符 operator overloading 学习笔记
    转 XMLHttpRequest().readyState的五种状态详解
    值得回味的基础知识理解加深
    完美解决fixed 水平居中问题
  • 原文地址:https://www.cnblogs.com/linda-fcj/p/7208342.html
Copyright © 2011-2022 走看看