• [NOIP 2012] 开车旅行


    题意:

    传送门

    题解:

    set+倍增。

    这题是一个高效模拟题,所以一般都要用一些比较高效的算法,小A和小B的路线都是固定的,所以很容易想到倍增来高效查询路线。

    那么设:
    g[i][j]表示从i开始往后(2^j)轮,车开到的城市。
    f[i][j][0]表示从i开始往后(2^j)轮,小A开车的路程。
    f[i][j][1]表示从i开始往后(2^j)轮,小B开车的路线。

    首先预处理出走一轮的路线,这个可以用set来实现。

    然后倍增转移。

    对于第一问,直接暴枚每个点为起点,比较一下即可。

    对于第二问,同理直接查询。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<map>
    #include<set>
    #define ll long long
    #define N 100010
    using namespace std;
    
    int h[N],g[N][22],f[N][22][2],dis[N][2],to[N][2];
    
    set<int> q;
    map<int,int> mp;
    
    int gi() {
      int x=0,o=1; char ch=getchar();
      while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
      if(ch=='-') o=-1,ch=getchar();
      while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
      return o*x;
    }
    
    void update(int x, int y) {
      int a=mp[x],b=mp[y],d=abs(x-y);
      if(!to[a][0] || d<dis[a][0] || (d==dis[a][0] && y<h[to[a][0]])) {
        to[a][1]=to[a][0],dis[a][1]=dis[a][0];
        to[a][0]=b,dis[a][0]=d;
      }
      else if(!to[a][1] || d<dis[a][1] || (d==dis[a][1] && y<h[to[a][0]])) {
        to[a][1]=b,dis[a][1]=d;
      }
    }
    
    void query(int x, int len, ll &a, ll &b) {
      for(int i=20; i>=0; i--) {
        if(g[x][i] && f[x][i][0]+f[x][i][1]<=len) {
          a+=f[x][i][0];
          b+=f[x][i][1];
          len-=f[x][i][0]+f[x][i][1];
          x=g[x][i];
        }
      }
      if(to[x][1] && dis[x][1]<=len) a+=dis[x][1]; 
    }
    
    int main() {
      int n=gi(),m,x,len,ans;
      ll ansa=0,ansb=0,a,b;
      for(int i=1; i<=n; i++) mp[h[i]=gi()]=i;
      for(int i=n; i>=1; i--) {
        q.insert(h[i]);
        set<int>::iterator it;
        it=q.find(h[i]);
        if(it!=q.begin()) {
          it--;
          update(h[i],*it);
          if(it!=q.begin()) {it--,update(h[i],*it),it++;}
          it++;
        }
        if((++it)!=q.end()) {
          update(h[i],*it);
          if((++it)!=q.end()) update(h[i],*it);
        }
      }
      for(int i=1; i<=n; i++) {
        g[i][0]=to[to[i][1]][0];
        f[i][0][0]=dis[i][1];
        f[i][0][1]=dis[to[i][1]][0];
      }
      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];
          f[i][j][1]=f[i][j-1][1]+f[g[i][j-1]][j-1][1];
        }
      len=gi();
      for(int i=1; i<=n; i++) {
        a=0,b=0;
        query(i,len,a,b);
        if(b && (!ansb || a*ansb<b*ansa || (a*ansb==b*ansa && h[i]>h[ans]))) ans=i,ansa=a,ansb=b;
      }
      printf("%d
    ", ans);
      m=gi();
      while(m--) {
        x=gi(),len=gi(),a=0,b=0;
        query(x,len,a,b);
        printf("%lld %lld
    ", a,b);
      }
      return 0;
    }
    
  • 相关阅读:
    vue 5 父子组件及组件间数据传递 学习代码片段
    微信小程序设置数组对象的值
    微信小程序样式拼接 类名三元运算 以及条件拼接
    超简易 消息通知滚动 pc移动适用
    js 批量监听-序号的闭包问题
    docker基础
    mysql
    mongodb
    django-restframework_认证
    SSM 整合
  • 原文地址:https://www.cnblogs.com/HLXZZ/p/7808983.html
Copyright © 2020-2023  润新知